Premessa
Ciao! Se ĆØ la prima volta che capiti su questo sito, ti consiglio di consultare la pagina principale di questo cosiddetto Giardino Digitale per scoprire meglio cosāĆØ e come navigarlo.
Lo stato di questa nota ĆØ al momento: š“ Bozza.
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 (fase 1 dellāalgoritmo), 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 (fase 2 dellāalgoritmo), e infine proviamo a trovare una soluzione (fase 3 dellāalgoritmo).
1 - 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 .
2 - 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:
3 - 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.
4 - 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.
5 - Estensioni dellāalgoritmo
Lāalgoritmo di inferenza può essere esteso a versioni del -calcolo con ulteriori tipi.
5.1 - 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 oppure oppure oppure allora lāalgoritmo fallisce perĀ errore di tipo.
5.2 - 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 .
5.3 - 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.
5.4 - 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, archiviato sulla Wayback MachineĀ in data 25 novembre 2025.
- š Simply typed lambda calculus su Wikipedia in lingua inglese, archiviato sulla Wayback Machine in data 25 novembre 2025.