Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli


Teoria dei Tipi e Semantica di Programmi Funzionali, Dispense di Elementi di Informatica

Paradigmi di Programmazione : lazy eager statico dinamico numeri di Church lamba calcolo call by value name reference - Sistemi dei Tipi : polimorfismo - Correttezza dei Programmi : logica di Hoare

Tipologia: Dispense

2016/2017

Caricato il 20/06/2017

andrea-rampello
andrea-rampello 🇮🇹

5

(1)

1 documento

1 / 100

Toggle sidebar

Questa pagina non è visibile nell’anteprima

Non perderti parti importanti!

bg1
Linguaggi di Programmazione
(dispense)
Pietro Cenciarelli
Universit`a di Roma, “La Sapienza”
27 febbraio 2016
Indice
1 Introduzione 4
I Nozioni Preliminari 10
2 Linguaggi 10
2.1 Automi ................................ 10
2.2 Grammatiche ............................. 10
2.3 Semantica ............................... 10
3 Struttura e rappresentazione 11
3.1 Induzione ............................... 11
3.2 Co-induzione ............................. 21
3.3 I tipi di dato nei linguaggi di programmazione . . . . . . . . . . . 24
II Paradigmi di Programmazione 26
4 Il Paradigma Funzionale 28
4.1 Exp : un semplice linguaggio funzionale . . . . . . . . . . . . . . . 28
4.1.1 Sintassi e semantica . . . . . . . . . . . . . . . . . . . . . 28
4.1.2 Equivalenza operazionale . . . . . . . . . . . . . . . . . . 31
4.1.3 Valutazione lazy ....................... 31
4.1.4 Valutazione lazy con scoping statico . . . . . . . . . . . . 32
4.1.5 Semantiche equivalenti . . . . . . . . . . . . . . . . . . . . 33
4.2 Fun: un linguaggio con funzioni . . . . . . . . . . . . . . . . . . 35
4.2.1 Sintassi e semantica . . . . . . . . . . . . . . . . . . . . . 35
4.2.2 Il lambda calcolo . . . . . . . . . . . . . . . . . . . . . . . 37
4.2.3 I numeri di Church . . . . . . . . . . . . . . . . . . . . . . 38
1
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d
pf4e
pf4f
pf50
pf51
pf52
pf53
pf54
pf55
pf56
pf57
pf58
pf59
pf5a
pf5b
pf5c
pf5d
pf5e
pf5f
pf60
pf61
pf62
pf63
pf64

Anteprima parziale del testo

Scarica Teoria dei Tipi e Semantica di Programmi Funzionali e più Dispense in PDF di Elementi di Informatica solo su Docsity!

Linguaggi di Programmazione

(dispense)

Pietro Cenciarelli

Universit`a di Roma, “La Sapienza”

1 Introduzione

Su un argomento il dibattito politico era il piu acceso nel paese di Lilliput: se le uova alla coque andassero mangiate aprendone il guscio dal lato piccolo o dal grande. I sostenitori del lato piccolo si chiamavano “little-endians” (piccolapun- tisti) , i loro avversari “big-endians” (grossapuntisti). La diatriba sie riaperta nell’era del computer, dove little-endians sono i sostenitori delle architetture n cui la rappresentazione interna di un numero incomincia dalla cifra meno signi- ficativa (Intel e Digital) e big-endians i fautori della piu significativa (Motorola, IBM e SUN). A tutt’oggi non ce un vincitore: nel linguaggio C, il programma

int main(void) { int i = 1; char *c = &i; printf("%d", *c); }

stampa 1 su un’architettura little-endian, 0 su una big-endian. Dunque, alla domanda

“qual `e il significato di un programma?”

non e ragionevole rispondere “e l’effetto che esso produce quando eseguito su un computer”, perch´e... su quale computer? La Semantica e la disciplina che studia il significato di un linguaggio. Nel caso specifico dei linguaggi di programmazione la semantica puo essere defi- nita formalmente. Una tale definizione costituisce una specifica non ambigua del linguaggio, e dunque uno strumento per il progettista del linguaggio ed un riferimento per l’implementatore e per il programmatore. Una semantica for- male consente inoltre l’applicazione di strumenti matematici nello studio del linguaggio. In particolare essa consente:

  • la sintesi di programmi da specifiche formali (per esempio espresse in UML). Questo viene fatto per garantire lo sviluppo di software corretto o per automatizzare la programmazione. In particolare e spessoe possibile generare automaticamente un compilatore o un interprete a partire da una specifica formale del linguaggio;
  • l’analisi di programmi, ovvero la verifica formale di propriet`a; ad esempio per applicazioni critiche.
  • lo studio della correttezza di compilatori, sia in fase di traduzione che di ottimizzazione; in generale, questo richiede una nozione di equivalenza fra programmi.

Sono possibili divesi approcci alla definizione di equivalenza. Si pu`o, ad esempio, decidere di considerare equivalenti due programmi quando producono

lo stesso risultato, oppure quando e possibile sostituire l’uno con l’altro in ogni contesto di programma senza cosı produrre effetti “visibili”. In genere queste due definizioni non descrivono la stessa relazione.

Esercizio∗^ 1.1 Sono equivalenti le seguenti versoni (una ricorsiva e l’altra iterativa) della funzione fattoriale?

int fact (int n) { if (n==0) return 1; else return n * fact(n-1); }

int fact_iter (int n) { if (n==0) return 1; int i, result = 1; for (i=1; i<=n; i++) result = result * i; return result; }

Semantica statica

Gli oggetti matematici hanno un tipo. Questa nozione si trova alle fondamenta della matematica stessa: distinguendo tra insiemi “grandi” e “piccoli”, ad esem- pio, si evita di incappare in paradossi quale “l’insieme di tutti gli insiemi che non contengono se stessi come elemento”, una versione insiemistica del barbiere che rade tutti e soli coloro che non si radono da soli (chi radera il barbiere?!). Nel trattare i programmi come oggetti matematici, una semantica formale deve dunque assegnare un tipo ai termini del linguaggio. Per semantica statica di un linguaggio di programmazione si intende il suo sistema dei tipi, ovvero l’insieme delle regole che consentono di dare un tipo ad espressioni, comandi ed altri costrutti di programmazione. La determinazione dei tipi none un puro esercizio di virtuosismo matema- tico. Lo scopo principale di un sistema dei tipi `e infatti quello di prevenire l’occorrenza di errori durante l’esecuzione di un programma. Esempi di tali errori vanno dall’applicazione di funzioni ad argomenti inappropriati, al rife- rimento illegale della memoria, al tentativo di dividere un numero per zero. Nei diversi linguaggi di programmazione sono stati adottati approcci diversi a questo problema: vi sono linguaggi esplicitamente tipati come il Pascal o L’Al- gol, implicitamente tipati, come ML o Haskell, o non tipati affatto, come il LISP o l’Assembler. Per garantire la sicurezza, ovvero il non insorgere di errori “inaspettati”, linguaggi non tipati ad alto livello come il LISP prevedono un meccanismo di controllo dei tipi (type checking) dinamico (ovvero a tempo di esecuzione).

operazionale, ma mappando i termini del linguaggio su oggetti matematici: nu- meri, elementi di strutture algebriche e cosı via. Per esempio, se ρ = (x, 2)e l’ambiente semantico che associa alla variabile x il valore 2 (nota la differenza con la costante 2 della semantica operazionale), allora:

[[(4+x)-3]]ρ = [[4+x]]ρ − [[ 3 ]]ρ = 3

dove con [[t]]ρ si intende il significato di t nell’ambiente ρ. Questo esempio mostra la composizionalita della semantica denotazionale: il significato di un’espressione complessa come (4+x)-3e una funzione del significato delle sue componenti piu semplici: (4+x) e 3. In generale la semantica denotazionalee piu astratta di quella operazionale. Nel caso precedente, ad esempio, la seconda ci da una informazione sull’ordine di valutazione degli operandi che non risulta dalla prima.

Semantica assiomatica. Il significato di un programma p e determinato nell’ambito di una teoria assiomatica dall’insieme delle proposizioni vere per p. In generale, questa semantica consente un approccio “meccanico” alla dimo- strazione formale di proprieta di programmi. Ad esempio, data una opportuna assiomatizzazione degli operatori if, for, :=, e cosı via,e possibile derivare formalmente la seguente proposizione:

{n ≥ 0 } fact(n); {res = n!}

dove {A} p {B} viene letta: “se il programma p, eseguito in uno stato che soddi- sfa la proprieta A, termina, allora lo stato da esso prodotto soddisfa la proprieta B”.

Le caratteristiche di un linguaggio

Nei manuali di programmazione il significato dei costrutti di un linguaggio viene di solito descritto facendo uso di nozioni semantiche quali quella di variabile, istruzione, sottoprogramma e cosı via. Di ciascuno di questi oggettie possibile specificare degli attributi. Ad esempio:

  • di una variabile:
    • il nome (ma esistono anche variabili anonime, cio`e senza nome);
    • l’area di memoria in cui `e mantenuto il suo valore;
  • di un sottoprogramma:
    • il nome;
    • i parametri formali con il loro tipo;
    • la modalit`a di passaggio dei parametri;
  • di un’istruzione:
  • le azioni ad essa associate.

Valori di tipo appropriato possono essere associati agli attributi delle entita di un programma tanto durante la compilazione quanto durante l’esecuzione. L’associazione di un valore ad uno o piu attributi di una entita si chiama binding (legame). Un fattore importante nell’analisi di un linguaggio di programmazionee il tempo di binding. Attributi diversi di una stessa entita possono essere legati in tempi diversi, ed un legame puo essere modificato durante l’esecuzione. Ad esempio: una variabile puo essere legata al suo tipo a tempo di compilazione ed al suo valore a tempo di esecuzione. Un legame si dice statico see stabilito prima dell’esecuzione e non pu`o essere cambiato in seguito, dinamico altrimenti. Ecco alcuni esempi di binding statico e dinamico

  • in Fortran ed in Ada il tipo INTEGER e legato al momento della defini- zione del linguaggio, mentre in Pascal il tipo integer puo essere ridefinito dal programmatore, e quindi legato alla sua rappresentazione a tempo di compilazione.
  • In Pascal una variabile viene legata al suo tipo a tempo di compilazione. In APL questo avviene a tempo di esecuzione: l’istruzione

A ← B + C

e corretta solo se, al momento dell’esecuzione, B e C contengono valori numerici, o sono matrici con lo stesso numero di dimensioni e grandezza. In generale, linguaggi in cui il legame di tipoe statico (Fortran, Pascal, Modula 2, Ada ecc.) sono anche detti fortemente tipati; quelli con legame dinamico (LISP, Snobol, APL, ecc.) sono anche detti non tipati.

  • L’allocazione di una zona di meoria per una variabile pu`o avvenire stati- camente (eseguita dal compilatore) o dinamicamente (eseguita a run time, sia automaticamente che dal programma, come con new in Java).
  • Il collegamento di una variabile con un valore e tipicamente dinamico. Una variabile con legame statico al valoree una costante simbolica (per distinguerla dalle costanti “letterali”, literal). In Pascal:

const pi = 3.14; circonferenza = 2 * pi * raggio;

In Pascal una costante viene tradotta dal compilatore nel suo valore. Le costanti dell’Algol 69 sono piu dinamiche: il loro valore viene determina- to a tempo di esecuzione, valutando una espressione che puo contenere variabili. In modo simile le variabili di tipo final di Java.

Parte I

Nozioni Preliminari

2 Linguaggi

2.1 Automi

2.2 Grammatiche

2.3 Semantica

3 Struttura e rappresentazione

How much is two? Paul Halmos - Naive Set Theory

3.1 Induzione

Per sintassi di un linguaggo di programmazione si intende generalmente un insieme di regole formali che definiscono le stringhe (ovvero le sequenze finite di simboli) del linguaggio. La sintassi e spesso definita usando la notazione BNF, ovvero mediante una grammatica libera dal contesto: il linguaggioe l’insieme delle stringhe di simboli terminali generabili mediante una derivazione, ovvero applicando le produzioni della grammatica. Va notato che le grammatiche libere dal contesto non sono generalmente adeguate ad esprimere vincoli sintattici quali la dichiarazione delle variabili prima dell’uso o la correttezza di una espressione dal punto di vista dei tipi. Una derivazione getta luce sulla struttura di una stringa, ovvero determina un albero sintattico. L’informazione sulla struttura, come ad esempio la precedenza da assegnare agli operatori nell’interpretazione di una espressione aritmetica, e necessaria per associare un significato agli elementi di un linguaggio (semantica). Una grammatica si dice ambigua se esiste piu di un albero sintattico per una stessa stringa. (Per una introduzione alle nozioni di grammatica, derivazione, albero sintattico... vd. [HMU03].) Affinch´e un compilatore o un interprete possano riconoscere le stringhe di un linguaggio, e necessario che questo sia definito da una grammatica non am- bigua. Esistono tecniche per disambiguare una grammatica o per trasformarne le produzioni in modo da rendere piu efficiente il riconoscimento, al costo pero di complicare, a volte in modo drammatico, gli alberi sintattici con struttura di scarsa rilevanza semantica. Per ovviare a questo inconveniente si ricorre, nello studio della semantica, all’uso della sintassi astratta. Come vedremo, la sintassi astratta none altro che una definizione induttiva. Il lettore ha probabilmente familiarita con l’induzione matematica, una tecnica per la dimostrazione di proprieta sui numeri naturali, e con definizioni induttive, quale ad esempio quella della funzione fattoriale. In questa sezione mostreremo che tecnica per definire funzioni o dimostrare proprieta sui numeri naturali, puo essere generalizzata ed applicata ad altri oggetti quali ad esempio gli alberi o, appunto, i termini di un linguaggio di programmazione. Il risultato della nostra investigazione sara l’ induzione strutturale, un principio generale di cui l’induzione matematica rappresenta un caso particolare. Iniziamo da cio che conosciamo: i numeri naturali.

I numeri naturali

Nel 1894 il matematico italiano Giuseppe Peano (1858 - 1932) propose una presentazione assiomatica dell’insieme N dei numeri naturali:

  1. 0 ∈ N ;

per induzione (ovvero per casi, uno per lo zero ed uno per il successore), cosa che nessuno delle altre proposte ci consente di fare. Consideriamo infatti l’usuale definizione della funzione fattoriale:

fact (0) = 1 fact (succ (n)) = succ (n) ∗ fact (n).

Se, violando il quinto assioma, scegliamo N> come modello dei naturali questa definizione risulta incompleta, perch´e non dice quanto vale fact (♥). Analoga- mente, la seguente definizione del predicato “essere pari”:

is even (0) = true is even (succ (n)) = not (is even (n))

darebbe risultati contraddittori se, in barba al quarto assioma, adottassimo il secondo modello dell’alieno, dove succ (1) = 1; dalle equazioni conseguirebbe infatti true = false. Considerazioni analoghe valgono per le dimostrazioni. Considerate infatti lo schema dell’induzione matematica:

P (0) P (n) ⇒ P (n + 1)) ∀ n. P (n)

Volendo usare questo schema per dimostrare, ad esempio, che tutti i naturali sono numeri primi, dovremmo scegliere come P (n) la proposizione “n e un numero primo”. Ora, se adottassimo N> come modello dei naturali, questo schema ci consentirebbe di dimostrare erroneamente che nessun elemento di N>,e uguale a ♥, incluso ahim´e ♥ stesso (si scelga come P (n) la proposizione “n e diverso da ♥”). Va notato che lo schema dell’induzione matematica altro none che il quinto assioma di Peano (che viene infatti chiamato principio di induzione) espresso usando la nozione di predicato al posto di quella di sottoinsieme. Infatti, un predicato P sui numeri naturali puo essere visto come un insieme SP ⊆ N , ovvero quel sottoinsieme dei numeri naturali che soddisfano la proprieta espressa dal predicato. L’assioma 5 ci dice che se 0 ∈ Sp (ovvero, se vale P (0)) ed inoltre se n ∈ Sp implica succ(n) ∈ SP (ovvero P (n) implica P (n + 1)), allora SP = N (ovvero, per ogni n ∈ N vale P (n)).

Torniamo ora alla domanda iniziale: quale tra gli infiniti modelli degli as- siomi di Peano e “il vero” insieme dei naturali? La rispostae: non importa, dato che tutti i modelli sono fra loro isomorfi. Se, insieme a von Neumann, l’alieno preferisce ℵ, faccia pure: come chiariremo ora, `e solo una faccenda di rappresentazione.

Algebre

L’insieme N dei numeri naturali, con l’operazione di somma e lo 0, elemento neutro dell’operazione, formano un’algebra detta monoide. La somma lavora su

due argomenti e viene percio detta binaria, o di arieta 2. Questo si indica sim- bolicamente attaverso una segnatura: N × N → N. Altre strutture algebriche sono, ad esempio, i gruppi. Il gruppo Z degli interi possiede, fra le altre, un’o- perazione Z → Z, di arieta 1, che associa ad ogni intero z il suo complemento −z. Vi sono poi strutture algebriche le cui operazioni usano (anche) argome- ni esterni all’algebra stessa: sull’algebra L delle liste di interi, ad esempio,e definita un’operazione cons : L × Z → L che aggiunge un intero ad una lista: cons (〈 2 , 5 〉, 7) = 〈 7 , 2 , 5 〉. In questo caso si dice che l’operazione e parametrica in Z. Le definizioni che seguono consentono di trattare in modo uniforme gli esempi fin qui riportati. Una segnatura algebricae costituita da un insieme I di nomi di funzione e, per ogni i ∈ I, un numero αi ≥ 0 ed una sequenza Ki = 〈Ki 1 ,... Kini 〉 di insiemi, i domini degli eventuali parametri esterni dell’operazione. Indichiamo con |Ki| la lunghezza della sequenza Ki. Il numero αi rappresenta, a meno di parametri esterni, l’arieta di i, che sara dunque αi + |Ki|. Per brevita di notazione scriveremo semplicemente I per indicare una segnatura. Abuseremo anche della notazione denotando con Ki l’insieme Ki 1 × · · · × Kini , mentre An indica come sempre il prodotto cartesiano di un insieme A per se stesso n volte. Un’algebra (A, γ) di segnatura Ie una struttura matematica costituita da un insieme A, chiamato carrier o insieme sottostante dell’algebra, ed una famiglia γ = {γi}i∈I di funzioni

γi : Aαi^ × Ki → A

chiamate operazioni fondamentali dell’algebra^1. Quando il contesto ci con- sentira di farlo senza ambiguita, useremo semplicemente A o γ per indicare un’algebra (A, γ). La somma, nel monoide dei naturali, e un’operazione di arieta 2 senza pa- rametri esterni (α+ = 2), mentre cons, nell’algebra delle liste, e un’operazione di arieta 2 con un parametro esterno (αcons = 1). Ora, cosa succede se, per qualche operazione i della segnatura, si ha αi = 0 (e, ad esempio, non vi sono parametri esterni)? In altre parole: cos’e una funzione nullaria, cioe con arieta 0? Consideriamo la coppia (7, 3). Essae un elemento dell’insieme N × N = N 2. La tripla (9, 2 , 6) `e un elemento di N × N × N = N 3. Dovremo allora convenire che () sia un elemento dell’insieme N 0 , l’unico! Dunque, indicando con 1 questo insieme, in analogia col mondo dei numeri dove n^0 = 1, si ha:

N 0 = {()} = 1.

Una funzione nullaria su un insieme A avra dunque segnatura 1 → A. Per semplicita assumeremo che, per ogni insieme X, l’equazione 1 × X = X valga in senso stretto. Dunque un’operazione γi di un’algebra A con αi = 0 e, ad esempio, un solo parametro esterno K avr`a segnatura K → A e non 1 ×K → A.

(^1) Algebre con parametri esterni sono dette eterogenee. Nei libri di algebra (vedi ad esempio [Lan93, BS81]) si considerano in genere operazioni senza parametri esterni. Questi rendo- no tutto un po’ pi`u complicato, ma sono qui necessari per trattare con strumenti algebrici strutture dati quali liste o alberi o, come vedremo oltre, i termini di una sintassi astratta.

  1. soddisfano il principio di induzione, ovvero: se un insieme S ⊆ A `e chiuso rispetto a ciascuna delle γi allora S = A.

Le γi sono chiamate costruttori di A. Un costruttore γi `e chiamato base se αi = 0. (^2)

Esercizio∗^ 3.4 Trovare un insieme di costruttori per i booleani {true, false}. La funzione not, lei da sola, soddisfa i requisiti? (^2)

Esercizio 3.5 Dimostrare che ogni algebra induttiva non vuota ha almeno un costruttore base. Dimostrare che ogni algebra induttiva non vuota con un costruttore non base `e necessariamente infinita. (^2)

Teorema 3.1 Sia A un’algebra induttiva. Per ogni algebra B con stessa segna- tura esiste un unico omomorfismo A → B.

Corollario 3.1 Due algebre induttive A e B con la stessa segnatura sono ne- cessariamente isomorfe.

Dimostrazione. Se f : A → B e g : B → A sono i due omomorfismi ottenuti applicando il Teorema 3.1 rispettivamente ad A e B, gli omomorfismi composti g · f : A → A e f · g : B → B devono coincidere necessariamente (per la condizione di unicita) con le identita, da cui l’isomorfismo. (^2)

Nella sezione 11.1 mostreremo che il teorema 3.1 costituisce il fondamen- to dello schema a clausole che si usa abitualmente in matematica per definire funzioni su insiemi induttivi, e che il linguaggio SML adotta per definire fun- zioni su datatype (vedi sezione 3.3). Il suo corollario, noto nella sua versione categoriale come lemma di Lambek , gioca invece un ruolo importante in que- sta sezione, perch´e ci consente di distinguere fra struttura e rappresentazione. Mentre in informatica l’implementazione che scegliamo per un tipo di dato puo avere un forte impatto sull’efficienza degli algoritmi che manipolano i dati, in matematica si tende a considerare irrilevante cio che distingue oggetti isomorfi. Il corollario 3.1 ci dice dunque che cio che in un insieme induttivoe matemati- camente rilevante e la struttura, chee data dalla sua segnatura; tutto il resto `e rappresentazione.

Torniamo all’insieme N dei numeri naturali. I primi due assiomi di Peano ci danno una segnatura algebrica:

0 : 1 → N succ : N → N.

Gli altri assiomi di Peano, 3, 4 e 5, corrispondono esattamente alle condizioni (rispettivamente) 2, 1 e 3 della Definizione 3.1. Questo ci dice che N e un’algebra induttiva, e cio `e quanto basta per definire (induttivamente) funzioni e dimo- strare teoremi (per induzione). Poi, per il lemma di Lambek, fa poca differenza rappresentare N come { 0 , 1 ,... } o come { { }, {{ }},... }.

Esercizio 3.6 Mostrare che esiste un isomorfismo algebrico tra l’insieme dei numeri naturali e l’insieme P = { 0 , 2 , 4 ,... } dei numeri pari, dove 0P = 0 e succP (n) = n + 2. (^2)

Esercizio 3.7 La funzione f : N> → ℵ tale che f (♥) = 0ℵ, f (0) = 1ℵ, f (1) = (^2) ℵ e biunivoca ma none un isomorfismo di algebre. Perch´e? (^2)

Esercizio 3.8 Scesi sulla terra, gli alieni ci parlano di algebra universale e, in particolare, di due insiemi, 2 e 4 , definiti induttivamente da costruttori con le seguenti segnature. C’`e qualcosa di simile, chiedono, sulla Terra?

  • 2 t : 1 → 2 f : 1 → 2
  • 4 l : 1 → 4 b : 4 × 4 → 4

2

Vediamo ora un altro esempio di algebra induttiva, quella degli alberi binari. Traiamo ispirazione dalla definizione induttiva di N : un numero naturale e zero, oppure il successore di un numero naturale. Analogamente, un albero binarioe una foglia, oppure una radice con un sottoalbero (binario) destro ed uno sinistro. Ecco due esempi di alberi binari ed un non-esempio:

^ TT

^ TT

^ TT

^ TT

^ TT

Questi sono solo disegni. Per spiegare ad un alieno la nozione di albero binario, si potrebbe dare la seguente definizione ricorsiva: l’insieme B-trees degli alberi binari `e quello definito induttivamente da due costruttori con la seguente segnatura: leaf : 1 → B-trees branch : B-trees × B-trees → B-trees

(... sı,e proprio 4 !). L’alieno e ora libero di immaginare gli alberi come meglio crede e di scegliere l’interpretazione che preferisce per i simboli leaf e branch: il lemma di Lambek garantise che, qualunque sia la scelta, la sua rappresentazione sara isomorfa alla nostra. Ora possiamo usare lo schema induttivo per definire funzioni su B-trees. Nella sezione 11.1 torneremo sul fondamento di questo schema; qui ci limiteremo a metterlo in pratica per definire la funzione leaves,

Alberi come grafi Nella teoria dei grafi un albero e un grafo non orientato nel quale due vertici sono connessi da uno ed un solo cammino. Un alberoe definito dunque in termini di una coppia (V, E) dove V e un insieme di vertici (assumia- molo finito) ed Ee un insieme di archi con particolari proprieta. In particolare, un albero radicatoe un albero nel quale ad un vertice viene conferito uno speciale status di “radice”. Da questa investitura deriva un orientamento naturale degli archi (che consiste nell’allontanarsi dalla race) ed una relazione padre-figlio. Se aggiungiamo poi il vincolo che ogni padre abbia esattamente due figli, ottenia- mo gli alberi binari. Che rapporto c’e fra gli alberi binari cosı ottenuti e gli elementi di B-trees? Ebbene: ne sono la versione commutativa! Notiamo infatti che mentre, per l’iniettivita dei costruttori, branch (t 1 , t 2 ) 6 = branch (t 2 , t 1 ) per t 1 6 = t 2 , negli alberi-grafo non c’e alcun ordinamento fra i figli di un nodo, e non ha dunque senso parlare di sottoalbero destro e sinistro. Per ottenere gli alberi- grafo (binari), dobbiamo dunque quozientare B-trees rispetto alla congruenza indotta dall’equazione branch (t 1 , t 2 ) = branch (t 2 , t 1 ). Gli alberi-grafo binari corrispondono allora alle classi di equivalenza indotte su B-trees dalla relazione che esprime la commutativita di branch. Quella degli “alberi commutativi”e un esempio di teoria algebrica, ovvero una teoria i cui assiomi sono equazioni. Altre teorie algebriche sono quella dei monoidi, dei gruppi, degli anelli, dove le equazioni impongono, ad esempio, l’associativit`a della moltiplicazione. Anche per algebre di questo tipo esiste un equivalente del teorema 3.1, ma questo ci porta oltre i limiti della nostra trattazione.

Sintassi Astratta

Sia L il linguaggio (un insieme di stringhe) generato dalla seguente grammatica.

Exp ::= 0 | 1 |... | Exp + Exp | Exp * Exp

Supponiamo di voler definire una funzione eval : L → N che valuta le espressioni del linguaggio. Se e 1 ed e 2 sono stringhe, indichiamo con e 1 +e 2 la stringa ottenuta concatenando le tre stringhe e 1 , " + " ed e 2. Ad esempio, "4" + "7" = "4 + 7".

eval ( 0 ) = 0 eval ( 1 ) = 1

... eval (e 1 + e 2 ) = eval (e 1 ) + eval (e 2 ) eval (e 1 * e 2 ) = eval (e 1 ) ∗ eval (e 2 )

Attenzione alla differenza tra 0 e 0, tra + e +, e cos`ı via. Ora, quanto fa eval (3 * 2 + 1)? Dipende:

eval (3 * 2 + 1) = eval ( 3 ) ∗ eval (2 + 1) = 3 ∗ 3 = 9, oppure eval (3 * 2 + 1) = eval (3 * 2) + eval ( 1 ) = 6 + 1 = 7.

Cio che abbiamo tentato di faree procedere per casi, cosı come avevamo fatto per fact o per leaves nelle sezioni precedenti. Cio che rende pero ac- cettabile la definizione di fact ma non quella di evale che la prima applica uno schema induttivo di definizione su un insieme definito induttivamente (N ), mentre la seconda tenta di applicare lo stesso schema ad un insieme (L) che induttivo non e. In effetti, ciascuna produzione della grammatica definisce un operatore su L. Ad esempio, Exp ::= Exp + Exp definisce l’operatore binario Plus : L × L → L tale che Plus ("3", "2 + 1") = "3 + 2 + 1". Analogamen- te, per il prodotto: Times ("3", "2 + 1") = "3 * 2 + 1", e cosı via. Questi operatori sintattici tuttavia non sono i costruttori del linguaggio, ovvero non definiscono L induttivamente. In particolare Plus e Times non hanno imma- gini disgiunte, visto che Times ("3", "2 + 1") = Plus ("3 * 2", "1"), da cui l’ambiguit`a nella definizione di eval.

La sintassi astratta di un linguaggio e una definizione induttiva di un insieme T di termini. Per esempio, la sintassi astratta del linguaggio delle espressionie data dalla seguente segnatura:

zero : 1 → T one : 1 → T

...... plus : T × T → T times : T × T → T

Ora la domanda `e: come sappiamo che un’algebra induttiva con questa segnatura esiste? La seguente costruzione ci assicura in tal senso.

Data una segnatura I, definiamo un’algebra (T, τ ) su I:

T 0 = ∅

T (^) n+1 = Tn ∪ { (i, t 1 ,... , tαi , k 1 ,... , k|Ki|) | i ∈ I, tj ∈ T (^) n, per j = 1... αi, e kl ∈ Kl, l = 1... |Ki| } T =

n≥ 0 T^ n

Le operazioni τi sono definite come segue:

τi(t 1 ,... , tn, k 1 ,... , kn) = (i, t 1 ,... , tn, k 1 ,... , km).

Va notato che, in accordo con quanto visto nell’esercizio 3.5, se non vi sono costruttori base in τ , T `e vuoto. Gli elementi di T sono chiamati termini, e T algebra dei termini su I.

Teorema 3.2 (T, α) `e un’algebra induttiva.

Torniamo alla nostra grammatica per le esperssioni. Abbiamo visto che essa definisce un’algebra (non induttiva) sul linguaggio L. Il teorema 3.2 ci d`a la sua