Per determinare se un termine Γ¨ ben tipato o meno si procede cercando di costruire un albero di derivazione ma, nel farlo, non ci Γ¨ sempre chiaro come procedere in maniera sistematica, come abbiamo visto nellβesempio di prima. Ecco che quindi vogliamo costruire un algoritmo che ci permetta di farlo sistematicamente: lβalgoritmo di inferenza.
Lβidea generale dellβalgoritmo di inferenza Γ¨ la seguente: innanzitutto ci dotiamo di un sistema grafico che ci permetta di operare facilmente sulle -espressioni, quindi proviamo a βintuireβ quali tipi potremmo assegnare ai sotto-termini della -espressione, creando dei collegamenti che ci permettano di porli in relazione tra di loro, e infine proviamo a trovare una soluzione.
Fase 1 dellβalgoritmo
Come giΓ detto, per il primo passo di questo algoritmo di inferenza ci serve un modo βvisivamente comodoβ per rappresentare le -espressioni. Per farlo, scegliamo una struttura ad albero esattamente come abbiamo fatto per lβalbero di derivazione, infatti questa nuova struttura sarΓ facilmente βtraducibileβ poi in un albero di derivazione proprio perchΓ© sono entrambi della forma ad albero.
Questa struttura verrΓ chiamata albero sintattico.
Definizione: albero sintattico
Data una -espressione , lβalbero sintattico Γ¨ una struttura ad albero definita induttivamente sulla forma sintattica del termine :
- Se Γ¨ un termine della forma di una variabile , allora sarΓ :
- Se Γ¨ un termine della forma di una costante , allora sarΓ :
- Se Γ¨ un termine della forma di unβastrazione , allora sarΓ :
- Se Γ¨ un termine della forma di unβapplicazione , allora sarΓ :
- Se Γ¨ un termine della forma di una struttura di controllo , allora sarΓ :
![]()
Esempio di albero sintattico
Ecco un esempio di albero sintattico della -espressione :
Esercizio 1 di costruzione di un albero sintattico
Costruisci lβalbero sintattico della -espressione .
Esercizio 2 di costruzione di un albero sintattico
Costruisci lβalbero sintattico della -espressione .
Fase 2 dellβalgoritmo
Dopo aver costruito lβalbero sintattico, si fa una visita dellβalbero usando la strategia bottom-up (quindi partendo dalle foglie e arrivando alla radice): ogni nodo viene βannotatoβ con unβespressione di tipo, ossia delle βetichetteβ che ci aiutano a intuire quale tipo potrebbe assumere quel nodo.
Definizione: espressione di tipo
Sia lβinsieme infinito di variabili di tipo.
Unβespressione di tipo Γ¨ unβetichetta assegnata a un nodo dellβalbero sintattico che corrisponde a una stringa ben formata a partire dalla seguente grammatica espressa in BNF:
dove:
- Γ¨ una variabile di tipo per un tipo ancora sconosciuto.
- Γ¨ il tipo booleano.
- Γ¨ il tipo funzione.
Per determinare delle βrelazioniβ tra le varie espressioni di tipo usiamo dei vincoli che devono essere rispettati affinchΓ© la -espressione sia ben tipata.
Definizione: vincolo
Un vincolo Γ¨ una relazione di uguaglianza tra due espressioni di tipo e :
Proviamo quindi a capire come annotare le espressioni di tipo sullβalbero sintattico distinguendo tra i vari casi.
Nel caso di un termine della forma di una variabile , nel nodo ci annotiamo un segnaposto , avendo cura di usare lo stesso segnaposto per tutte le occorrenze di e solo per quelle:
Nel caso di un termine della forma di una costante , nel nodo ci annotiamo il tipo booleano :
Nel caso di un termine della forma di unβastrazione , partendo dal basso (perchΓ© stiamo usando la strategia bottom-up):
- Dal sotto-albero avremo ottenuto unβespressione di tipo .
- Nel nodo ci annotiamo un tipo funzione , dove Γ¨ un segnaposto (e, per ogni occorrenza di in , dovremo usare sempre lo stesso segnaposto ) e Γ¨ lβespressione di tipo del sotto-albero .
Il risultato Γ¨ il seguente:
Nel caso di un termine della forma di unβapplicazione , partendo sempre dal basso (perchΓ© stiamo usando la strategia bottom-up):
- Dal sotto-albero avremo ottenuto unβespressione di tipo (dove Γ¨ diverso dal usato nellβastrazione , perchΓ© questi due sotto-termini non sono la stessa cosa).
- Dal sotto-albero avremo ottenuto unβespressione di tipo .
- Nel nodo ci annotiamo un nuovo segnaposto .
- Generiamo un nuovo vincolo .
Il risultato Γ¨ il seguente:
In particolare, se Γ¨ di un certo tipo funzione , allora il nodo ha tipo e il vincolo generato Γ¨ :
Nel caso di un termine della forma di una struttura di controllo :
- Dal sotto-albero avremo ottenuto unβespressione di tipo .
- Dal sotto-albero avremo ottenuto unβespressione di tipo .
- Dal sotto-albero avremo ottenuto unβespressione di tipo .
- Generiamo il vincolo che richiede che il tipo di sia booleano: .
- Generiamo il vincolo che richiede che il tipo di e di coincida: .
- Nel nodo ci annotiamo il tipo (), che sarΓ proprio il tipo che restituisce la struttura di controllo.
Il risultato Γ¨ il seguente:
Fase 3 dellβalgoritmo
Nella terza fase dellβalgoritmo di inferenza, una volta che lβalbero sintattico Γ¨ stato annotato, si cerca di capire se questo insieme di vincoli ammette una soluzione e si cerca di trovare quella generale da cui derivare tutte le altre.
Allβinizio della terza fase ci ritroviamo con un sistema di vincoli:
Per risolvere questo sistema usiamo un algoritmo di risoluzione.
Algoritmo di risoluzione
Dato un sistema di vincoli , lβalgoritmo di risoluzione permette di risolvere , ottenendo un successo o un fallimento.
I passi da seguire sono i seguenti:
- Per ogni vincolo , verificare se nella seguente tabella il vincolo rispetta una delle seguenti forme e condizioni e, eventualmente, eseguire la trasformazione indicata:
Forma del vincolo Condizione Cosa fare Γ¨ unβespressione di tipo qualsiasi Eliminare il vincolo Γ¨ unβespressione di tipo qualsiasi e Γ¨ un segnaposto Rimpiazzare il vincolo con e sono due espressioni di tipo qualsiasi Rimpiazzare il vincolo con e e sono due espressioni di tipo qualsiasi, Γ¨ il tipo booleano Lβalgoritmo fallisce per errore di tipo e sono due espressioni di tipo qualsiasi, Γ¨ il tipo booleano Lβalgoritmo fallisce per errore di tipo Γ¨ unβespressione di tipo qualsiasi, Γ¨ un segnaposto e compare in Lβalgoritmo fallisce per errore di occorrenza Γ¨ unβespressione di tipo qualsiasi, Γ¨ un segnaposto e non compare in Rimpiazzare le occorrenze di con in tutti gli altri vincoli e lasciando questo invariato
- Ripetere il passo 1 finchΓ© non si ottiene un fallimento dellβalgoritmo o finchΓ© non Γ¨ piΓΉ possibile applicare le trasformazioni indicate.
- Se non Γ¨ avvenuto un fallimento dellβalgoritmo, allora ha avuto successo e si Γ¨ risolto il sistema .
Osservazione: invarianza dell'ordine delle trasformazioni
Lβordine in cui si applicano le trasformazioni del passo 1 dellβalgoritmo di risoluzione non influisce sul risultato.
Con il successo dellβalgoritmo di risoluzione, avremo ottenuto un nuovo sistema di vincoli
dove ogni Γ¨ un segnaposto (che compare una sola volta nel sistema) corrispondente esattamente a un tipo che sarΓ uguale a unβespressione di tipo .
A questo punto non ci rimane altro che fare una sostituzione di ogni con il rispettivo .
Definizione: sostituzione
Nellβalgoritmo di inferenza, una sostituzione Γ¨ una funzione da variabili di tipo a espressioni di tipo in cui, dato un tipo , sostituiamo in ogni occorrenza di ogni sotto-tipo con la sostituzione .
Da questa sostituzione otteniamo una possibile soluzione dellβalgoritmo di inferenza.
Definizione: soluzione
Nellβalgoritmo di inferenza, dato un sistema di vincoli e una sostituzione , diciamo che Γ¨ una soluzione (o unificatore) del sistema se, per ogni :
Attenzione: differenza tra gli nella definizione di soluzione
Nella definizione di soluzione, i due che compaiono rispettivamente nel sistema di vincoli e nella relazione di uguaglianza non significano la stessa cosa: mentre nel primo caso serve solo come βpromemoriaβ per ricordarsi di come sono βcollegateβ tra di loro le espressioni di tipo, nel secondo indica una vera e propria uguaglianza tra i risultati delle sostituzioni.
In particolare, usando lβalgoritmo di risoluzione per βridurre al minimoβ il sistema di vincoli, otterremo non una soluzione qualsiasi ma la soluzione piΓΉ generale, che ci permette di ricavare a partire da essa tutte le altre possibili soluzioni.
Definizione: soluzione piΓΉ generale
Nellβalgoritmo di inferenza, dato un sistema di vincoli e una soluzione , diciamo che Γ¨ la soluzione piΓΉ generale (o unificatore piΓΉ generale) del sistema se ogni soluzione del sistema Γ¨ ottenibile componendo con unβaltra sostituzione.
Definizione dellβalgoritmo
Dopo aver esplicitato il funzionamento dellβalgoritmo di inferenza attraverso le 3 fasi di cui si compone, possiamo finalmente dichiararlo formalmente.
Algoritmo di inferenza
Data una -espressione , lβalgoritmo di inferenza permette di inferire il tipo di .
I passi da seguire sono i seguenti:
- Costruire lβalbero sintattico .
- Su ogni nodo dellβalbero sintattico annotare delle espressioni di tipo e generare i rispettivi vincoli seguendo questa tabella:
Contenuto del nodo Cosa annotare Vincoli da generare Risultato sullβalbero sintattico Termine della forma di una variabile Nel nodo : un segnaposto , avendo cura di usare lo stesso segnaposto per tutte le occorrenze di e solo per quelle Termine della forma di una costante Nel nodo : il tipo booleano Termine della forma di unβastrazione Nel nodo : un tipo funzione , dove Γ¨ un segnaposto (e, per ogni occorrenza di in , dovremo usare sempre lo stesso segnaposto ) e Γ¨ lβespressione di tipo del sotto-albero Termine della forma di unβapplicazione con con espressione di tipo qualsiasi Nel nodo : un segnaposto , dove Γ¨ lβespressione di tipo del sotto-albero e Γ¨ lβespressione di tipo del sotto-albero Termine della forma di unβapplicazione con con espressione di tipo Nel nodo : il tipo , dove Γ¨ lβespressione di tipo del sotto-albero Termine della forma di una struttura di controllo Nel nodo : il tipo , dove Γ¨ lβespressione di tipo del sotto-albero , dove Γ¨ lβespressione di tipo del sotto-albero
, dove Γ¨ lβespressione di tipo del sotto-albero e Γ¨ lβespressione di tipo del sotto-albero
- Sul sistema di vincoli usare lβalgoritmo di risoluzione.
- Se lβalgoritmo di risoluzione ha fallito, allora la -espressione non Γ¨ ben tipata.
- Se lβalgoritmo di risoluzione ha avuto successo, effettuare su ogni vincolo del nuovo sistema la sostituzione.
- Il risultato del passo 5 Γ¨ la soluzione piΓΉ generale del sistema.
Estensioni dellβalgoritmo
Lβalgoritmo di inferenza puΓ² essere esteso a versioni del -calcolo con ulteriori tipi.
Estensione con i numeri interi
Possiamo, per esempio, aggiungere tra i tipi anche i numeri interi , sotto forma del tipo :
Di conseguenza, nella definizione del termine basterΓ specificare che le costanti potranno assumere come valori anche i numeri interi :
e, nella forma sintattica della struttura di controllo , potrΓ assumere solo i valori e .
Nellβalgoritmo di inferenza non si notano particolari differenze, ma:
- Tra le espressioni di tipo, annoverare tra le possibili forme anche .
- Nella tabella di generazione dei vincoli, specificare che ai termine della forma di una costante va assegnato il tipo giusto a seconda del valore che assume, quindi:
- Nellβalgoritmo di risoluzione, aggiungere che, se cβΓ¨ un vincolo della forma o o o allora lβalgoritmo fallisce perΒ errore di tipo.
Estensione con le liste
Questa volta, tra i tipi annoveriamo anche le liste, costituite da elementi di tipo :
Ovviamente, ciΓ² implica che anche tra le espressioni di tipo dobbiamo annoverare tra le possibili forme anche .
Nei valori possibili che puΓ² assumere un termine-costante, ci includiamo i due costruttori canonici delle liste, la lista vuota e il cons :
In particolare, in Haskell il costruttore lista vuota ha tipo e il costruttore cons ha tipo :
Tenendo conto che nella stessa -espressione possiamo costruire liste di elementi di tipo diverso (per esempio, possono coesistere in una -espressione una lista di tipo e una lista di tipo ), abbiamo che le costanti dei costruttori canonici delle liste (cioè e ) devono essere interpretate come costanti polimorfe, cioè in ogni loro occorrenza possono assumere tipo diverso.
Per questo motivo, nella fase di generazione dei vincoli dellβalgoritmo di inferenza, per ogni occorrenza di uno di questi due costruttori dobbiamo stare attenti ad annotare nel nodo tipi che usano segnaposti freschi: se, per esempio, in un nodo trovo , lo annoto come una lista di elementi che hanno come tipo un segnaposto ; se lo troverΓ² una seconda volta, lo annoterΓ² come una lista di elementi che hanno come tipo un segnaposto e cosΓ¬ via:
Per quanto riguarda la fase di risoluzione dei vincoli, se abbiamo vincoli che impongono lβuguaglianza di tipi che hanno forme palesemente diverse (per esempio , o ) allora lβalgoritmo fallisce per errore di tipo.
Abbiamo anche un caso analogo a quello dei tipi funzioni in cui possiamo semplificare lβuguaglianza di due funzioni () imponendo lβuguaglianza dei domini e dei codomini ( e ): se cβΓ¨ un vincolo allora possiamo rimpiazzarlo con .
Estensione con funzioni di libreria
In generale, possiamo estendere lβalgoritmo di inferenza assumendo che nelle espressioni da tipare compaiano le funzioni della libreria standard di Haskell (es. id, head, tail, β¦), che potranno essere funzioni polimorfe (ossia il loro tipo non Γ¨ un tipo specifico ma Γ¨ una variabile di tipo) e per trattarle in questo modo va fatto come abbiamo appena fatto per le liste: ogni occorrenza deve usare nuove variabili di tipo (segnaposti) per ogni occorrenza.
Estensione con definizioni ricorsive
Potremmo volere stabilire il tipo di una definizione ricorsiva della forma
dove puΓ² comparire in .
Quel che dobbiamo fare Γ¨ aggiungere il vincolo dove Γ¨ la variabile di tipo associata a e Γ¨ lβannotazione di .
Fonti
- π« Corso di Laurea in Informatica (
L-31 R) presso lβUniversitΓ di Torino:
- Corso di Linguaggi e Paradigmi di Programmazione, A.A. 2020-21 (pagina Moodle):
- Prof. Luca Padovani, slide del corso:
- Prof. Luca Padovani, videoregistrazioni del corso:
- Corso di Linguaggi e Paradigmi di Programmazione, A.A. 2025-26 (pagina Moodle):
- Prof. Viviana Bono,Β lezioni del corso.
- π Lambda-calcolo su Wikipedia in lingua italiana, URL consultato lβultima volta eΒ archiviatoΒ il 25 novembre 2025.
- π Simply typed lambda calculus su Wikipedia in lingua inglese, URL consultato lβultima volta e archiviato il 25 novembre 2025.
- π§ Consultazione di ChatGPT.