Tutti ne parlano..



"I linguaggi artificiali, o linguaggi di programmazione, sono gli strumenti con cui si comunica con i calcolatori, ed in particolare li si istruisce sui compiti che si desidera vengano svolti. Un generico calcolatore è in grado di svolgere un  insieme vastissimo di compiti, che vanno dal calcolo numerico alla video-grafica, dalla simulazione di realtà virtuali,  al controllo di processi meccanici.
Un calcolatore è una struttura molto complessa, che possiamo immaginare fatta a strati come una cipolla: lo strato più interno è quello dove effettivamente vengono compiute le operazioni, che sono pochissime e molto elementari: essenzialmente operazioni aritmetiche, spostamento di informazioni da un posto all’altro, confronto tra diversi valori. Queste operazioni sono codificate in linguaggio-macchina, le cui parole sono stringhe binarie (cioè composte solo di due caratteri, 0 e 1): un linguaggio contemporaneamente elementare e difficilissimo da capire per un essere umano. In effetti chi vuole programmare un calcolatore non usa questo linguaggio, ma usa un linguaggio cosidetto di programmazione,  che ha una struttura più vicina ai linguaggi naturali ed è quindi più facilmente comprensibile per una persona. Il programma,  cioè la sequenza di istruzioni scritta in questo linguaggio, viene poi automaticamente analizzato e, tramite diversi passi di traduzione, riscritto nel linguaggio-macchina: a questo punto la sequenza di comandi da esso codificata può essere eseguita. Quindi i linguaggi di programmazione devono essere comprensibili sia per le persone umane che per le macchine. Esiste un gran numero di linguaggi di programmazione, alcuni disegnati espressamente per agire in ambienti specifici, altri (la maggior parte) di carattere generale, che si prestano a programmare praticamente qualunque tipo di applicazione. Ma che cosa hanno in comune tutti questi linguaggi? Quali caratteristiche li distinguono dai linguaggi naturali, quelli che usiamo per comunicare tra esseri umani? Perché ne esistono tanti?

Un linguaggio, sia esso naturale o artificiale, presenta due aspetti: la sintassi, cioè l’insieme di regole che ci permette di costruire frasi corrette, e la semantica, che assegna un significato alle frasi. Per i linguaggi di programmazione, bisogna che tutti e due questi aspetti siano automatizzabili. Infatti i procedimenti di traduzione, dal linguaggio originale in linguaggio-macchina, possono essere effettivi solo se è possibile in modo automatico:
1.       verificare se il programma è sintatticamente corretto  (analisi sintattica),
2.       in caso positivo, assegnargli un significato (analisi semantica).
La fattibilità dell’analisi sintattica si raggiunge tramite le grammatiche formali, che definiscono in modo esaustivo le regole sintattiche. Un esempio molto semplice è la grammatica per generare i numerali in notazione decimale corrispondenti a numeri interi non negativi. La grammatica è formata dalle seguenti due regole:
1.       <cifra>::= 0|1|2|….|9
2.       <numero>::= <cifra>|<numero><cifra>
Le parole tra parentesi acute definiscono classi di oggetti del linguaggio. Una regola si intepreta nel modo seguente: il simbolo a sinistra del segno ::= può essere sostituito da una delle sequenze di simboli che occorrono alla sua destra, separate dal segno |. Un simbolo non parentetizzato rappresenta un oggetto del linguaggio, e quindi non può più essere sostituito (viene anche detto oggetto terminale della grammatica). Nel caso particolare, la regola 1 definisce cos’è una cifra, dando l’insieme dei valori che essa può assumere, la regola 2 descrive le modalità di costruzione di un numero, che o concide con una cifra o si può ottenere da un numero precedentemente costruito semplicemente postponendogli una cifra.
In generale, per un linguaggio di programmazione esistono varie grammatiche, dipendenti una dall’altra, che lo definiscono: una grammatica per le parole, una per le frasi, e una per i discorsi compiuti, o programmi.

La differenza essenziale tra linguaggi artificiali e quelli naturali è nella semantica. I linguaggi naturali servono per comunicare con esseri (presumibilmente)  intelligenti, mentre l’interlocutore dei linguaggi di programmazione è un’entità assolutamente priva di intelligenza: una macchina. Tutte le ricchezze del linguaggio naturale sono perciò bandite dai linguaggi di programmazione, in particolare l’ambiguità semantica. L’ambiguità semantica permette che una frase abbia più di un significato, a seconda del contesto in cui si viene a trovare, o non ne abbia nessuno se non in un contesto simbolico o metaforico. Una frase semanticamente ambigua è la seguente: “La vecchia porta la sbarra”. L’ambiguità è evidente se la considera inserita in due diversi contesti, nel modo seguente: “ La vecchia porta la sbarra: lo sforzo piega il suo corpo stanco” e “La donna fugge correndo dal suo assalitore verso la cantina, ma la vecchia porta la sbarra”. La frase è ambigua in quanto alcune parole che la compongono possono avere doppio significato (porta e sbarra), ma si possono costruire frasi semanticamente ambigue anche a partire da parole che ambigue non sono. Consideriamo la frase: “L’uomo guardava la ragazza  col cannocchiale”:  il cannocchiale può essere il mezzo con cui l’uomo guarda la ragazza, e questa è l’interpretazione più naturale, ma potrebbe anche essere tenuto in mano dalla ragazza. Noi non facciamo normalmente caso all’ambiguità del nostro linguaggio, in quanto automaticamente capaci (quasi sempre!) di discernere il significato corretto, ma essa permea la comunicazione tra gli esseri umani e offre loro possibilità  di esprimere costrutti raffinati come l’ironia, le metafore, la poesia.
Però è esperienza comune la necessità di usare un linguaggio tanto più semplice e preciso quanto più è stupido il nostro interlocutore (con tutto il rispetto per gli stupidi!). Quindi, poiché la macchina è l’essere più stupido in assoluto, i linguaggi di programmazione devono essere tali che ogni frase abbia uno e un solo significato. La non ambiguità semantica si ottiene in modo incrementale: si associa un significato ad ogni parola, e poi si definisce il significato di una frase in funzione del significato delle singole parole, e così via…

Inoltre, i linguaggi di programmazione devono possedere un’altra proprietà:  la sostituibilità semantica. Cioè sostituendo una parte di un discorso (o programma) con un’altra di uguale significato, il significato dell’intero discorso non deve cambiare. Nei linguaggi naturali la sostituibilità semantica non vale, e questo è conseguenza non solo dell’ambiguità semantica, ma di due altri fattori: l’uso di frasi definitorie, e la possibilità di usare la stessa parola in veste di significante e di significato. Consideriamo la frase definitoria:” Roma è la capitale d’Italia”: in essa non possiamo sostituire la parola Roma con il suo significato, altrimenti otteniamo la frase: “La capitale d’Italia è la capitale d’Italia”, che è una tautologia e ha un significato diverso rispetto alla definizione di partenza. Nella frase: “otto è palindroma”, la parola “otto” è usata come significante, non come significato, quindi la sua sostituzione con “quattro più quattro”, che pure ha lo stesso significato, rende la stessa frase un non senso. Nei linguaggi di programmazione non è che queste due costruzioni non si possano esprimere, ma si esplicita nella sintassi il diverso uso delle parole. Quindi la definizione si introduce con una costruzione sintattica particolare, e quando una parola è usata come significante si esplicita questo uso con un’apposita funzione.
La sostituibilità semantica permette di riutilizzare programmi come pezzi di altri programmi, e quindi di risparmiare lavoro.

I linguaggi di programmazione, inoltre, devono possedere una potenza espressiva apparentemente enorme, adeguata per programmare ogni possibile applicazione.

In conclusione, i linguaggi di programmazione sono linguaggi che devono possedere  le seguenti caratteristiche: una sintassi precisa, una semantica non ambigua, la sostituibilità  semantica e un potere espressivo che ci permetta di dare a un calcolatore qualunque ordine  esso sia in grado di svolgere.
Sono caratteristiche molto chiare, ma non suggeriscono nulla sulla struttura di tali linguaggi: come si fa a inventare un linguaggio artificiale? A cosa ci si può ispirare?

Per quanto apparentemente  molto diversi l’uno dall’altro, i linguaggi di programmazione si possono raggruppare in classi, o paradigmi, ciascuno dei quali nasce da un’idea astratta di calcolo. E’ interessante notare come alcuni dei paradigmi più usati nascano da un’idea di programmazione nata prima dell’invenzione del calcolatore stesso, e precisamente da un problema che i matematici si sono posti intorno agli anni ’30: quali funzioni matematiche possono essere effettivamente calcolate? Una funzione è una relazione che lega in modo deterministico una sequenza  di valori dati (detti argomenti) a uno specifico risultato. Un esempio è la funzione somma di numeri interi, che ad ogni coppia di numeri interi associa il valore della loro somma (e noi sappiamo per esperienza che questa funzione può essere effettivamente calcolata).
A questa domanda hanno risposto diversi grandi matematici, come Turing, Kleene, Church, Post e altri. Per rispondere, ciascuno di essi ha innanzitutto dovuto definire cosa significa calcolare effettivamente. Tutti hanno concordato sul fatto che calcolare effettivamente significa calcolare in modo automatico, ma, poiché allora non esistevano i calcolatori, ciascuno di essi ha definito una propria nozione di calcolo  automatico, con risultati tra di loro molto diversi. Il risultato interessante è stato che, se pure partendo da definizioni di computazione diverse, tutti hanno trovato la stessa classe di funzioni, che appunto viene definita classe delle funzioni calcolabili.

Poiché tra i compiti che il calcolatore deve svolgere c’è quello di calcolare, ogni linguaggio di programmazione deve essere in grado di esprimere almeno tutte le funzioni calcolabili. "
-Simona Ronchi Della Rocca


E' stato riportato, in parte, un articolo di una professoressa universitaria che si occupa di informatica. Non per simpatia, ma perchè racchiude quasi totalmente l'argomento dei linguaggi artificiali. E' evidente come si possa arrivare a una conclusione semplice: il linguaggio artificiale può continuamente essere sostituito da uno nuovo, per trovare metodi più efficienti ogni volta che ce ne sia la necessità.

Commenti