"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
Posta un commento