DI RECENTE ACCOMAZZI...
CERCA
» Ricerca avanzata
MAILING LIST

Se vuoi iscriverti alla mailing list di Luca Accomazzi inserisci qui la tua mail:

Vuoi ricevere i messaggi immediatamente (50 invii / giorno) o in differita e in gruppo
(due invii / giorno)?

» Vuoi saperne di più?

Quanti linguaggi conosci?

Quando un programmatore parla del suo lavoro con altre persone, molto spesso si ritrova a spiegare cosa è un programma e come è possibile che governi un computer, dato che molte persone non hanno nessuna conoscenza di informatica. Nei casi restanti, quando l'interlocutore ha una infarinatura di computer science, magari perché si trova ogni giorno a lottare in ufficio con Lotus 1-2-3, prima o poi si arriva di fronte ad una domanda, una domanda sussurrata in tono imbarazzato come se stessimo parlando delle più intime confidenze: ma tu, quanti linguaggi conosci?

In effetti, dopo aver padroneggiato i primi, poniamo, tre linguaggi, aggiungerne altri alla collezione è molto semplice. Spesso restano confusi i particolari, ma un ripasso di cinque minuti prima di mettersi alla tastiera basta ed avanza. Per chiarire meglio questo punto, basti dire che in tutti i linguaggi che conosciamo esiste il costrutto for per la ripetizione; e la sintassi di quel comando è differente in ciascuno...

Pochi, però, conoscono una intera famiglia di linguaggi di programmazione: i linguaggi funzionali.
Se ci pensate, noterete che tutti i linguaggi che conoscete hanno una struttura molto simile e che il loro costrutto di base è la scrittura di una unità di programma (che in Basic si chiama subroutine, in Pascal procedura e in C funzione); l'unità di programma viene poi usata poi insieme ad altre per scrivere il programma principale. Anche negli Assembler esiste il concetto di subroutine.
Un'altra pietra miliare è la variabile. In tutti i linguaggi esistono variabili di vario tipo: intere, reali, stringhe...

Nei linguaggi funzionali, invece, le variabili non esistono: è questa la loro caratteristica principale. Anche le procedure sono severamente ridimensionate: esistono solo sotto la forma di funzioni, cio] sottoprogrammi che debbono restituire un valore.
L'idea di base è che le variabili servono solo a intorbidare le acque: dato che il loro valore cambia continuamente, il programmatore non puo averle veramente sotto controllo.

E c'è di peggio: quando in un programma viene invocata una unità subroutine, il che è concettualmente semplice, possono nascere i temuti effetti collaterali (per gli anglofili, meglio conosciuti come side effects ).
Prendete il pezzo di programma...

Variabile_Uno := 5;
Chiamo Subroutine_Alfa (Variabile_Uno);
Stampa (Variabile_Uno);

Secondo voi, cosa verrà stampato? Se siete tra gli ottimisti, convinti che verrà stampato il numero 5, ripensateci. Se non ne siete tanto sicuri, avete già intuito cosa stiamo per scoprire.
Fatto sta che la Subroutine_Alfa può fare qualunque cosa: tra le azioni possibili c'è anche la modifica del valore della Variabile_Uno. Pertanto, anche se risulta molto naturale supporre che la variabile resti immutata, nulla lo garantisce.
Se il nome della procedura è, per esempio, Incremento La Variabile Che Mi Passate Come Argomento, il problema non sussiste. Ma potrebbe darsi che lo scopo della procedura sia semplicemente di controllare l'esistenza di un file sul disco, e che ciononostante la Variabile_Uno sia incrementata per qualche oscuro motivo legato al codice scritto per realizzare la procedura.

C'è di peggio. Tutti voi sapete, sino dalle scuole elementari, che la addizione è un'operazione commutativa. Questo significa che A + B da sempre lo stesso risultato di B + A.
Immaginate ora per un momento di aver scritto una subroutine
che restituisce un valore (una funzione Pascal, in Basic il risultato del comando Def Fn). Per esempio, questa funzione restituisce il quadrato del numero che voi passate come parametro, così:

FUNCTION Quadrato (Argomento: integer): integer;
BEGIN
Quadrato := Argomento * Argomento
END;

Tutto chiaro? Adesso lasciate che io faccia una piccola modifica, apparentemente molto stupida. Potete immaginare che una cosa del genere avvenga in un programma vero, in una funzione lunga molte centinaia di righe, per qualche strano motivo.

FUNCTION Quadrato (VAR Argomento: integer): integer;
BEGIN
Quadrato := Argomento * Argomento;
Argomento := Argomento + 1
END;

E adesso, guardate i due programmi che seguono:

(* programma numero uno *)
A := 4;
B := Quadrato (A) + A;

(* Programma numero due *)
A := 4;
B := A + Quadrato (A);

Quel che succede è che la addizione non è più commutativa. Nel primo caso, B risulta uguale a 21, mentre nel secondo caso risulta uguale a 20. In entrambi i casi, alla fine A è uguale a 5.

Questa caratteristica dei linguaggi di programmazione tradizionali (il nome tecnico è di linguaggi procedurali) è piuttosto pericolosa. In particolare, diviene molto difficile provare con mezzi matematici la correttezza di un programma, cio] dimostrare matematicamente che un programma fa effettivamente quello che dovrebbe fare. Esistono metodi per eseguire una simile dimostrazione, ma crollano platealmente in taluni casi e comunque sono complicati e lunghi. Per dimostrare che un programma di dieci righe funziona, potrebbero essere necessarie due ore di calcoli.
Al contrario, è possibile provare formalmente la correttezza dei programmi creati nei linguaggi funzionali. Anzi, è possibile scrivere programmi che provano la correttezza di questi programmi, il che non è affatto poco.

Per di più, c'è una costante tendenza nella ricerca a volgersi in quella direzione. I linguaggi funzionali sono tradizionalmente lenti e poco efficienti, ma con l'aumentare della potenza delle macchine questo aspetto diviene poco importante.
Il Kernel-Zero, il linguaggio macchina dei futuri computer della quinta generazione, è sostanzialmente un linguaggio funzionale. Non varrebbe la pena di aggiungere un linguaggio funzionale ai (quanti?) linguaggi che conoscete?