15.08.2013 Views

Alice Troise - Lambda calcolo e tipi polimorfi - SELP

Alice Troise - Lambda calcolo e tipi polimorfi - SELP

Alice Troise - Lambda calcolo e tipi polimorfi - SELP

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Polimorfismo parametrico<br />

e type reconstruction<br />

<strong>Alice</strong> <strong>Troise</strong><br />

Università degli Studi di Firenze<br />

Polimorfismo parametrico – p. 1


Polimorfismo<br />

Polimorfismo parametrico – p. 2


Polimorfismo<br />

La necessità di avere <strong>polimorfi</strong>smo nei linguaggi nasce da due<br />

importanti obiettivi, in parte contrastanti:<br />

Polimorfismo parametrico – p. 2


Polimorfismo<br />

La necessità di avere <strong>polimorfi</strong>smo nei linguaggi nasce da due<br />

importanti obiettivi, in parte contrastanti:<br />

riusabilità del codice<br />

Polimorfismo parametrico – p. 2


Polimorfismo<br />

La necessità di avere <strong>polimorfi</strong>smo nei linguaggi nasce da due<br />

importanti obiettivi, in parte contrastanti:<br />

riusabilità del codice<br />

e<br />

typing statico (essendo le variabili legate ai <strong>tipi</strong> prima della fase<br />

runtime, siamo sicuri che quando il programma sarà in esecuzione non<br />

avverranno errori di tipo)<br />

Polimorfismo parametrico – p. 2


Polimorfismo<br />

La necessità di avere <strong>polimorfi</strong>smo nei linguaggi nasce da due<br />

importanti obiettivi, in parte contrastanti:<br />

riusabilità del codice<br />

e<br />

typing statico (essendo le variabili legate ai <strong>tipi</strong> prima della fase<br />

runtime, siamo sicuri che quando il programma sarà in esecuzione non<br />

avverranno errori di tipo)<br />

Nel presente approfondimento viene descritto il <strong>polimorfi</strong>smo<br />

parametrico implicito (parametri di tipo type e applicazioni di<br />

tipo non sono ammesse) applicato al linguaggio del λ-<strong>calcolo</strong>.<br />

Polimorfismo parametrico – p. 2


Polimorfismo<br />

La necessità di avere <strong>polimorfi</strong>smo nei linguaggi nasce da due<br />

importanti obiettivi, in parte contrastanti:<br />

riusabilità del codice<br />

e<br />

typing statico (essendo le variabili legate ai <strong>tipi</strong> prima della fase<br />

runtime, siamo sicuri che quando il programma sarà in esecuzione non<br />

avverranno errori di tipo)<br />

Nel presente approfondimento viene descritto il <strong>polimorfi</strong>smo<br />

parametrico implicito (parametri di tipo type e applicazioni di<br />

tipo non sono ammesse) applicato al linguaggio del λ-<strong>calcolo</strong>.<br />

Iniziamo col ricordare sintassi, semantica e typing del λ-<strong>calcolo</strong>.<br />

Polimorfismo parametrico – p. 2


Sintassi del λ-<strong>calcolo</strong><br />

t ::= termini :<br />

x variabile<br />

λx : T.t astrazione (a la Church)<br />

tt applicazione<br />

v ::= valori :<br />

λx : T.t astrazione<br />

T ::= <strong>tipi</strong> :<br />

T → T freccia<br />

Γ ::= contesti :<br />

∅ contesto vuoto<br />

Γ, x : T binding di variabile<br />

Polimorfismo parametrico – p. 3


Estensione alla sintassi del λ-<strong>calcolo</strong><br />

t ::= termini :<br />

true, false, 0 booleani e zero<br />

if t then t else t costrutto if<br />

succ t successore<br />

pred t predecessore<br />

iszero t test sullo zero<br />

v ::= valori :<br />

true, false booleani<br />

nv (0 o succ nv) valori numerici<br />

T ::= <strong>tipi</strong> :<br />

Nat, Bool naturali e booleani<br />

Polimorfismo parametrico – p. 4


Semantica del λ-<strong>calcolo</strong><br />

t1 → t ′ 1<br />

t1t2 → t ′ 1 t2<br />

t2 → t ′ 2<br />

v1t2 → v1t ′ 2<br />

(E-APP1)<br />

(E-APP2)<br />

(λx: T.t)v → [x ↦→ v]t (E-APPABS)<br />

Polimorfismo parametrico – p. 5


Estensione alla semantica del λ-<strong>calcolo</strong><br />

t1 → t ′ 1<br />

iszero t1 → iszero t ′ 1<br />

(E-ISZERO)<br />

iszero 0 → true (E-ISZEROZ)<br />

iszero(succ nv1) → false (E-ISZEROS)<br />

t1 → t ′ 1<br />

if t ′ 1 then t2 else t3<br />

(E-IF)<br />

if true then t2 else t3 → t2 (E-IFTRUE)<br />

if false then t2 else t3 → t3 (E-IFFALSE)<br />

Polimorfismo parametrico – p. 6


Estensione alla semantica del λ-<strong>calcolo</strong><br />

t1 → t ′ 1<br />

pred t1 → pred t ′ 1<br />

t1 → t ′ 1<br />

succ t1 → succ t ′ 1<br />

(E-PRED)<br />

(E-SUCC)<br />

pred(succ nv1) → nv1 (E-PREDSUCC)<br />

pred 0 → 0 (E-PREDZERO)<br />

Polimorfismo parametrico – p. 7


Typing del λ-<strong>calcolo</strong><br />

x : T ∈ Γ<br />

Γ ⊢ x : T<br />

Γ,x : T1 ⊢ t2 : T2<br />

Γ ⊢ λx : T1.t2 : T1 → T2<br />

Γ ⊢ t1 : T11 → T12 Γ ⊢ t2 : T11<br />

Γ ⊢ t1t2 : T12<br />

(T-VAR)<br />

(T-ABS)<br />

(T-APP)<br />

Polimorfismo parametrico – p. 8


Estensione al typing del λ-<strong>calcolo</strong><br />

Γ ⊢ true : Bool (T-TRUE) Γ ⊢ false : Bool (T-FALSE)<br />

Γ ⊢ 0 : Nat (T-ZERO)<br />

Γ ⊢ t1 : Nat<br />

Γ ⊢ succt1 : Nat<br />

(T-SUCC)<br />

Γ ⊢ t1 : Nat<br />

Γ ⊢ iszero t1 : Bool<br />

Γ ⊢ t1 : Nat<br />

Γ ⊢ predt1 : Nat<br />

Γ ⊢ t1 : Bool Γ ⊢ t2 : T Γ ⊢ t3 : T<br />

Γ ⊢ if t1 then t2 else t3 : T<br />

(T-IF)<br />

(T-ISZERO)<br />

(T-PRED)<br />

Polimorfismo parametrico – p. 9


Variabili di tipo e sostituzioni<br />

Aggiungiamo al linguaggio del λ-<strong>calcolo</strong>, esteso coi valori<br />

numerici e qualche funzione, un insieme infinito A di <strong>tipi</strong> base<br />

non interpretati senza operazioni primitive associate. Questi <strong>tipi</strong><br />

sconosciuti prendono il nome di variabili di tipo e vengono<br />

indicati con X, Y, Z, ....<br />

Polimorfismo parametrico – p. 10


Variabili di tipo e sostituzioni<br />

Aggiungiamo al linguaggio del λ-<strong>calcolo</strong>, esteso coi valori<br />

numerici e qualche funzione, un insieme infinito A di <strong>tipi</strong> base<br />

non interpretati senza operazioni primitive associate. Questi <strong>tipi</strong><br />

sconosciuti prendono il nome di variabili di tipo e vengono<br />

indicati con X, Y, Z, ....<br />

Il processo che assegna <strong>tipi</strong> concreti a variabili di tipo è chiamato<br />

sostituzione oppure istanziazione.<br />

Polimorfismo parametrico – p. 10


Le due fasi della sostituzione<br />

È conveniente separare le operazioni di sostituzione in due parti:<br />

Polimorfismo parametrico – p. 11


Le due fasi della sostituzione<br />

È conveniente separare le operazioni di sostituzione in due parti:<br />

1. descrizione del mapping σ dalle variabili di tipo nei <strong>tipi</strong>,<br />

chiamato sostituzione<br />

Polimorfismo parametrico – p. 11


Le due fasi della sostituzione<br />

È conveniente separare le operazioni di sostituzione in due parti:<br />

1. descrizione del mapping σ dalle variabili di tipo nei <strong>tipi</strong>,<br />

chiamato sostituzione<br />

2. applicazione del mapping ad un particolare tipo T per<br />

ottenere una istanza σT .<br />

Polimorfismo parametrico – p. 11


Le due fasi della sostituzione<br />

È conveniente separare le operazioni di sostituzione in due parti:<br />

1. descrizione del mapping σ dalle variabili di tipo nei <strong>tipi</strong>,<br />

chiamato sostituzione<br />

2. applicazione del mapping ad un particolare tipo T per<br />

ottenere una istanza σT .<br />

֒→ Esempio: possiamo definire [X ↦→ Bool,Y ↦→ X → Int].<br />

Se applichiamo σ al tipo X ↦→ X otteniamo Bool → Bool.<br />

Se applichiamo σ al tipo Y otteniamo X → Int.<br />

Polimorfismo parametrico – p. 11


Sostituzione di tipo - definizione<br />

Def. Sostituzione di tipo: mapping finito σ da variabili di tipo<br />

in <strong>tipi</strong>.<br />

Polimorfismo parametrico – p. 12


Sostituzione di tipo - definizione<br />

Def. Sostituzione di tipo: mapping finito σ da variabili di tipo<br />

in <strong>tipi</strong>.<br />

Scriviamo dom(σ) per indicare l’insieme delle variabili di tipo<br />

che appaiono a sinistra delle coppie di σ; range(σ) per l’insieme<br />

dei <strong>tipi</strong> che appaiono a destra.<br />

Polimorfismo parametrico – p. 12


Sostituzione di tipo - definizione<br />

L’applicazione di una sostituzione ad un tipo è definita nel<br />

seguente modo:<br />

σ(X) =<br />

⎧<br />

⎨<br />

⎩<br />

σ(Nat) = Nat<br />

σ(Bool) = Bool<br />

σ(T1 → T2) = σT1 → σT2<br />

T se (X ↦→ T) ∈ σ<br />

X se X /∈ dom(σ)<br />

Polimorfismo parametrico – p. 13


Sostituzione di tipo - definizione<br />

La sostituzione di tipo si estende banalmente ad un contesto di<br />

assunzioni di tipo Γ definendo:<br />

σ(x1 : T1,...,xn : Tn) = (x1 : σT1,...,xn : σTn)<br />

Polimorfismo parametrico – p. 14


Sostituzione di tipo - definizione<br />

La sostituzione di tipo si estende banalmente ad un contesto di<br />

assunzioni di tipo Γ definendo:<br />

σ(x1 : T1,...,xn : Tn) = (x1 : σT1,...,xn : σTn)<br />

Se σ e γ sono sostituzioni, scriviamo σ ◦ γ per identificare la<br />

sostituzione formata dalla composizione di esse:<br />

⎡<br />

X ↦→ σ(T) per ogni (X ↦→ T) ∈ γ<br />

σ◦γ = ⎣<br />

X ↦→ T per ogni (X ↦→ T) ∈ σ con X /∈ dom(γ)<br />

Si noti che (σ ◦ γ)S = σ(γS).<br />

⎤<br />

⎦<br />

Polimorfismo parametrico – p. 14


Preservation del typing<br />

Teorema: Il buon tipaggio si preserva sotto sostituzione di tipo,<br />

ovvero ∀σ Γ ⊢ t : T ⇒ σΓ ⊢ σt : σT.<br />

Dimostrazione: Per induzione sulla derivazione del tipo<br />

Polimorfismo parametrico – p. 15


Istanze di sostituzione valide<br />

Sia t un termine contenente variabili di tipo, Γ un contesto<br />

associato; ci chiediamo se può essere istanziato a un termine ben<br />

tipato scegliendo appropriati valori per le sue variabili di tipo.<br />

Polimorfismo parametrico – p. 16


Istanze di sostituzione valide<br />

Sia t un termine contenente variabili di tipo, Γ un contesto<br />

associato; ci chiediamo se può essere istanziato a un termine ben<br />

tipato scegliendo appropriati valori per le sue variabili di tipo.<br />

֒→ Per esempio, sia Γ = {f : F, x : X} e sia t = fx. t non è tipabile così<br />

com’è, ma lo può essere con una qualsiasi delle seguenti sostituzioni:<br />

[F ↦→ Nat → Bool, X ↦→ Nat] ed in questo modo ha tipo Bool.<br />

[F ↦→ X → Nat] ed in questo modo t ha tipo Nat;<br />

[F ↦→ X → Y] ed in questo modo ha tipo Y;<br />

Polimorfismo parametrico – p. 16


Istanze di sostituzione valide<br />

Sia t un termine contenente variabili di tipo, Γ un contesto<br />

associato; ci chiediamo se può essere istanziato a un termine ben<br />

tipato scegliendo appropriati valori per le sue variabili di tipo.<br />

֒→ Per esempio, sia Γ = {f : F, x : X} e sia t = fx. t non è tipabile così<br />

com’è, ma lo può essere con una qualsiasi delle seguenti sostituzioni:<br />

[F ↦→ Nat → Bool, X ↦→ Nat] ed in questo modo ha tipo Bool.<br />

[F ↦→ X → Nat] ed in questo modo t ha tipo Nat;<br />

[F ↦→ X → Y] ed in questo modo ha tipo Y;<br />

La ricerca di istanze di sostituzione valide porta all’idea di type<br />

reconstruction (o type inference), nella quale il compilatore<br />

completa le informazioni di tipo non specificate dal<br />

programmatore.<br />

Polimorfismo parametrico – p. 16


Verso un typing vincolato<br />

Nelle prossime slides presenteremo un algoritmo che, dato un<br />

termine t ed un contesto Γ, trova le condizioni minime sulle loro<br />

variabili di tipo per rendere t ben tipato.<br />

Polimorfismo parametrico – p. 17


Verso un typing vincolato<br />

Nelle prossime slides presenteremo un algoritmo che, dato un<br />

termine t ed un contesto Γ, trova le condizioni minime sulle loro<br />

variabili di tipo per rendere t ben tipato.<br />

La differenza con l’ordinario algoritmo di typechecking è che,<br />

invece di controllare che siano soddisfatte certe condizioni, le<br />

registra per una considerazione successiva.<br />

Polimorfismo parametrico – p. 17


Vincoli - definizioni<br />

Un insieme di vincoli (constraint) C è un insieme di equazioni<br />

C = {S1 = T1, S2 = T2, ..., Sn = Tn}.<br />

Polimorfismo parametrico – p. 18


Vincoli - definizioni<br />

Un insieme di vincoli (constraint) C è un insieme di equazioni<br />

C = {S1 = T1, S2 = T2, ..., Sn = Tn}.<br />

Si dice che una sostituzione σ unifica un’equazione Si = Ti se<br />

σSi = σTi.<br />

Si dice che σ soddisfa C se σ unifica tutte le equazioni di C.<br />

Polimorfismo parametrico – p. 18


Typing basato sui vincoli<br />

La relazione Γ ⊢ t : T|χC è letta “il termine t ha tipo T nel<br />

contesto delle assunzioni Γ ogni qual volta i vincoli C sono<br />

soddisfatti”.<br />

Polimorfismo parametrico – p. 19


Typing basato sui vincoli<br />

La relazione Γ ⊢ t : T|χC è letta “il termine t ha tipo T nel<br />

contesto delle assunzioni Γ ogni qual volta i vincoli C sono<br />

soddisfatti”.<br />

Il simbolo χ è usato per tenere traccia delle variabili di tipo<br />

introdotte; tali annotazioni assicurano che:<br />

1. ogni qual volta una variabile di tipo è scelta dalla regola<br />

finale di una certa derivazione, è sicuro che essa è diversa<br />

da ogni altra variabile scelta fra le sotto-derivazioni;<br />

2. ogni volta che una regola coinvolge due o più<br />

sotto-derivazioni, gli insiemi delle variabili scelte da tali<br />

sotto-derivazioni sono disgiunti.<br />

Polimorfismo parametrico – p. 19


Regole typing con vincoli 1<br />

x : T ∈ Γ<br />

Γ ⊢ x : T|∅{}<br />

Γ, x : T1 ⊢ t2 : T2|χC<br />

Γ ⊢ λx : T1.t2 : T1 → T2|χC<br />

Γ ⊢ t1 : T1|χ1C1 Γ ⊢ t2 : T2|χ2C2<br />

χ1 ∩ χ2 = χ1 ∩ FV (T2) = χ2 ∩ FV (T1) = ∅<br />

X /∈ χ1,χ2, T1, T2, C1, C2, Γ, t1, t2<br />

Γ ⊢ t1t2 : X|χ1∪χ2∪{X}C1 ∪ C2 ∪ {T1 = T2 → X}<br />

dove indichiamo con FV(T) l’insieme di tutte le variabili di tipo<br />

menzionate in T.<br />

(CT-VAR)<br />

(CT-ABS)<br />

(CT-APP)<br />

Polimorfismo parametrico – p. 20


Regole typing con vincoli 2<br />

Γ ⊢ true : Bool|∅{} (CT-TRUE)<br />

Γ ⊢ false : Bool|∅{} (CT-FALSE)<br />

Γ ⊢ t1 : T1|χ1C1 Γ ⊢ t2 : T2|χ2C2 Γ ⊢ t3 : T3|χ3C3<br />

χ1,χ2,χ3 nonoverlapping<br />

Γ ⊢ if t1 then t2 else t3 : T2|χ1∪χ2∪χ3 C ′<br />

dove C ′ = C1 ∪ C2 ∪ C3 ∪ {T1 = Bool, T2 = T3}<br />

(CT-IF)<br />

Polimorfismo parametrico – p. 21


Regole typing con vincoli 3<br />

Γ ⊢ 0 : Nat|∅{} (CT-ZERO)<br />

Γ ⊢ t1 : T|χC<br />

Γ ⊢ predt1 : Nat|χC ∪ {T = Nat}<br />

Γ ⊢ t1 : T|χC<br />

Γ ⊢ succt1 : Nat|χC ∪ {T = Nat}<br />

Γ ⊢ t1 : T|χC<br />

Γ ⊢ iszero t1 : Bool|χC ∪ T = Nat<br />

(CT-PRED)<br />

(CT-SUCC)<br />

(CT-ISZERO)<br />

Polimorfismo parametrico – p. 22


Osservazioni<br />

• Il sistema di typing con vincoli è guidato dalla sintassi del<br />

linguaggio.<br />

Polimorfismo parametrico – p. 23


Osservazioni<br />

• Il sistema di typing con vincoli è guidato dalla sintassi del<br />

linguaggio.<br />

• Le regole definiscono una procedura deterministica,<br />

ovvero un algoritmo che dato un termine t ed un contesto Γ<br />

ricava il tipo T e l’insieme C tali che Γ ⊢ t : T|χC.<br />

Polimorfismo parametrico – p. 23


Osservazioni<br />

• Il sistema di typing con vincoli è guidato dalla sintassi del<br />

linguaggio.<br />

• Le regole definiscono una procedura deterministica,<br />

ovvero un algoritmo che dato un termine t ed un contesto Γ<br />

ricava il tipo T e l’insieme C tali che Γ ⊢ t : T|χC.<br />

• Questo algoritmo non fallisce mai: per ogni Γ e per ogni t<br />

vi è sempre un tipo T ed un contesto C tali che Γ ⊢ t : T|χC.<br />

Questo in quanto i vincoli non vengono verificati<br />

all’interno delle regole, ma vengono solo memorizzati in C<br />

per un’analisi successiva.<br />

Polimorfismo parametrico – p. 23


Esempio di derivazione di tipo<br />

֒→ Derivazione di tipo per il termine λx : X. λy : Y.xy<br />

x : X ∈ Γ<br />

y : Y ∈ Γ<br />

{x : X, y : Y} ⊢ x : X| ∅{} {x : X, y : Y} ⊢ y : Y| ∅{}<br />

{x : X, y : Y} ⊢ (xy) : W| {W}{X = Y → W}<br />

{x : X} ⊢ λy : Y.(xy) : Y → W| {W}{X = Y → W}<br />

{} ⊢ λx : X. λy : Y.(xy) : X → Y → W| {W}{X = Y → W}<br />

Polimorfismo parametrico – p. 24


Esempio di derivazione di tipo<br />

֒→ Derivazione di tipo per il termine λx : X. λy : Y.xy<br />

x : X ∈ Γ<br />

y : Y ∈ Γ<br />

{x : X, y : Y} ⊢ x : X| ∅{} {x : X, y : Y} ⊢ y : Y| ∅{}<br />

{x : X, y : Y} ⊢ (xy) : W| {W}{X = Y → W}<br />

{x : X} ⊢ λy : Y.(xy) : Y → W| {W}{X = Y → W}<br />

{} ⊢ λx : X. λy : Y.(xy) : X → Y → W| {W}{X = Y → W}<br />

ricordando la regola CT-ABS:<br />

Γ, x : T1 ⊢ t2 : T2|χC<br />

Γ ⊢ λx : T1.t2 : T1 → T2|χC<br />

Polimorfismo parametrico – p. 24


Esempio di derivazione di tipo<br />

֒→ Derivazione di tipo per il termine λx : X. λy : Y.xy<br />

x : X ∈ Γ<br />

y : Y ∈ Γ<br />

{x : X, y : Y} ⊢ x : X| ∅{} {x : X, y : Y} ⊢ y : Y| ∅{}<br />

{x : X, y : Y} ⊢ (xy) : W| {W}{X = Y → W}<br />

{x : X} ⊢ λy : Y.(xy) : Y → W| {W}{X = Y → W}<br />

{} ⊢ λx : X. λy : Y.(xy) : X → Y → W| {W}{X = Y → W}<br />

ricordando la regola CT-ABS:<br />

Γ, x : T1 ⊢ t2 : T2|χC<br />

Γ ⊢ λx : T1.t2 : T1 → T2|χC<br />

ricordando la regola CT-APP:<br />

Γ ⊢ t1 : T1|χ1 C1 Γ ⊢ t2 : T2|χ2 C2<br />

χ1 ∩ χ2 = χ1 ∩ FV (T2) = χ2 ∩ FV (T1) = ∅ X fresh<br />

Γ ⊢ t1t2 : X| χ1∪χ2∪{X}C1 ∪ C2 ∪ {T1 = T2 → X}<br />

Polimorfismo parametrico – p. 24


Osservazioni pratiche<br />

Normalmente la costruzione della derivazione coi vincoli non<br />

avviene con un solo passaggio; ciò significa che inizialmente<br />

verranno identificati i <strong>tipi</strong> delle variabili senza supporre alcunchè<br />

sui vincoli (raggiungeremo cioè la cima della derivazione in<br />

modo bottom up). Successivamente, a partire dalla parte alta<br />

della derivazione (ovvero dalla definizione degli elementi<br />

inizialmente appartenenti al contesto), verranno costruiti<br />

l’insieme dei vincoli ed il tipo S mediante l’applicazione delle<br />

regole semantiche.<br />

Polimorfismo parametrico – p. 25


Soluzioni<br />

Soluzione per (Γ, t)<br />

Sia Γ un contesto di assunzioni di tipo e t un termine. Una<br />

soluzione per (Γ, t) è una coppia (σ, T) tale che σΓ ⊢ σt : T.<br />

Soluzione per (Γ, t, S, C)<br />

Sia Γ ⊢ t : S|C. Una soluzione per (Γ, t, S, C) è una coppia<br />

(σ, T) tale che σ soddisfa C e σS = T.<br />

Polimorfismo parametrico – p. 26


Soluzioni<br />

Soluzione per (Γ, t)<br />

Sia Γ un contesto di assunzioni di tipo e t un termine. Una<br />

soluzione per (Γ, t) è una coppia (σ, T) tale che σΓ ⊢ σt : T.<br />

Soluzione per (Γ, t, S, C)<br />

Sia Γ ⊢ t : S|C. Una soluzione per (Γ, t, S, C) è una coppia<br />

(σ, T) tale che σ soddisfa C e σS = T.<br />

Correttezza: Sia Γ ⊢ t : S|C. Se (σ, T) è una soluzione per<br />

(Γ, t, S, C), allora è anche una soluzione per (Γ, t).<br />

Completezza: Sia Γ ⊢ t : S|C. Se (σ, T) è una soluzione per<br />

(Γ, t), allora è anche una soluzione per (Γ, t, S, C).<br />

Dimostrazione: per induzione (si veda Pierce [1])<br />

Polimorfismo parametrico – p. 26


Completezza del typing vincolato<br />

In realtà la formulazione del teorema di completezza è<br />

leggermente diversa.<br />

Def.: σ\χ è una sostituzione indefinita per tutte le variabili in χ<br />

e con le altre si comporta come σ.<br />

Teorema di completezza: Sia Γ ⊢ t : S|C. Se (σ, T) è una<br />

soluzione per (Γ, t) e dom(σ) ∩ χ = ∅ allora esiste una<br />

soluzione (σ ′ , T) per (Γ, t, S, C) tale che σ ′ \χ = σ.<br />

Polimorfismo parametrico – p. 27


Unificazione<br />

Per calcolare le soluzioni di un insieme di vincoli usiamo<br />

l’algoritmo di unificazione di Robinson (1971).<br />

Polimorfismo parametrico – p. 28


Unificazione<br />

Per calcolare le soluzioni di un insieme di vincoli usiamo<br />

l’algoritmo di unificazione di Robinson (1971).<br />

Def. Sostituzione meno specifica: Una sostituzione σ è meno<br />

specifica (o più generale) di una sostituzione σ ′ , scritto σ ⊑ σ ′ ,<br />

se σ ′ = γ ◦ σ per qualche sostituzione γ.<br />

Polimorfismo parametrico – p. 28


Unificazione<br />

Per calcolare le soluzioni di un insieme di vincoli usiamo<br />

l’algoritmo di unificazione di Robinson (1971).<br />

Def. Sostituzione meno specifica: Una sostituzione σ è meno<br />

specifica (o più generale) di una sostituzione σ ′ , scritto σ ⊑ σ ′ ,<br />

se σ ′ = γ ◦ σ per qualche sostituzione γ.<br />

Def. Unificatore principale: Un unificatore principale per un<br />

insieme di vincoli C è una sostituzione σ che soddisfa C e tale<br />

che σ ⊑ σ ′ per ogni sostituzione σ ′ che soddisfa C.<br />

Polimorfismo parametrico – p. 28


Unificazione<br />

Per calcolare le soluzioni di un insieme di vincoli usiamo<br />

l’algoritmo di unificazione di Robinson (1971).<br />

Def. Sostituzione meno specifica: Una sostituzione σ è meno<br />

specifica (o più generale) di una sostituzione σ ′ , scritto σ ⊑ σ ′ ,<br />

se σ ′ = γ ◦ σ per qualche sostituzione γ.<br />

Def. Unificatore principale: Un unificatore principale per un<br />

insieme di vincoli C è una sostituzione σ che soddisfa C e tale<br />

che σ ⊑ σ ′ per ogni sostituzione σ ′ che soddisfa C.<br />

Def. Algoritmo di unificazione: Vedi pseudo-codice nella<br />

prossima slide.<br />

Polimorfismo parametrico – p. 28


Algoritmo di unificazione<br />

unify(C) =<br />

- if C = ∅ then [ ]<br />

- else let {S = T} ∪ C ′ = C in<br />

Polimorfismo parametrico – p. 29


Algoritmo di unificazione<br />

unify(C) =<br />

- if C = ∅ then [ ]<br />

- else let {S = T} ∪ C ′ = C in<br />

- if S = T<br />

- then unify(C ′ )<br />

- else if S = X and X /∈ FV(T)<br />

- then unify([X ↦→ T]C ′ ) ◦ [X ↦→ T]<br />

- else if T = X and X /∈ FV(S)<br />

- then unify([X ↦→ S]C ′ ) ◦ [X ↦→ S]<br />

Polimorfismo parametrico – p. 29


Algoritmo di unificazione<br />

unify(C) =<br />

- if C = ∅ then [ ]<br />

- else let {S = T} ∪ C ′ = C in<br />

- if S = T<br />

- then unify(C ′ )<br />

- else if S = X and X /∈ FV(T)<br />

- then unify([X ↦→ T]C ′ ) ◦ [X ↦→ T]<br />

- else if T = X and X /∈ FV(S)<br />

- then unify([X ↦→ S]C ′ ) ◦ [X ↦→ S]<br />

- else if S = S1 → S2 and T = T1 → T2<br />

- then unify(C ′ ∪ {S1 = T1, S2 = T2})<br />

Polimorfismo parametrico – p. 29


Algoritmo di unificazione<br />

unify(C) =<br />

- if C = ∅ then [ ]<br />

- else let {S = T} ∪ C ′ = C in<br />

- if S = T<br />

- then unify(C ′ )<br />

- else if S = X and X /∈ FV(T)<br />

- then unify([X ↦→ T]C ′ ) ◦ [X ↦→ T]<br />

- else if T = X and X /∈ FV(S)<br />

- then unify([X ↦→ S]C ′ ) ◦ [X ↦→ S]<br />

- else if S = S1 → S2 and T = T1 → T2<br />

- then unify(C ′ ∪ {S1 = T1, S2 = T2})<br />

- else<br />

- fail<br />

Polimorfismo parametrico – p. 29


Osservazioni su unify<br />

• La frase “let {S = T}∪C ′ = C” alla seconda linea deve<br />

essere intesa come “si scelga un vincolo S = T dall’insieme<br />

C e sia C ′ l’insieme che denota i rimanenti vincoli di C.<br />

Polimorfismo parametrico – p. 30


Osservazioni su unify<br />

• La frase “let {S = T}∪C ′ = C” alla seconda linea deve<br />

essere intesa come “si scelga un vincolo S = T dall’insieme<br />

C e sia C ′ l’insieme che denota i rimanenti vincoli di C.<br />

• Le condizioni di lato X /∈ FV(T) e X /∈ FV(S) sono note<br />

come occur check. Servono per impedire all’algoritmo di<br />

generare una soluzione che contenga una sostituzione<br />

ciclica come ad esempio X ↦→ X → X.<br />

Polimorfismo parametrico – p. 30


Osservazioni su unify<br />

• La frase “let {S = T}∪C ′ = C” alla seconda linea deve<br />

essere intesa come “si scelga un vincolo S = T dall’insieme<br />

C e sia C ′ l’insieme che denota i rimanenti vincoli di C.<br />

• Le condizioni di lato X /∈ FV(T) e X /∈ FV(S) sono note<br />

come occur check. Servono per impedire all’algoritmo di<br />

generare una soluzione che contenga una sostituzione<br />

ciclica come ad esempio X ↦→ X → X.<br />

• Nel nostro caso il fallimento dell’algoritmo può avvenire o<br />

per occur check o perché tentiamo di unificare Nat = Bool.<br />

Polimorfismo parametrico – p. 30


Proprietá di unify<br />

Teorema (Milner):<br />

1. unify(C) termina per ogni C;<br />

2. se unify(C)=σ, allora σ è un unificatore per C;<br />

3. se δ è un unificatore per C, allora unify(C)=σ con σ ⊑ δ<br />

Dimostrazione: Vedi Pierce [1]<br />

Polimorfismo parametrico – p. 31


Soluzione principale<br />

Def. Soluzione e tipo principale: Una soluzione principale per<br />

(Γ, t, S, C) è una soluzione (σ, T) tale che, per ogni altra<br />

soluzione (σ ′ , T ′ ) si ha che σ ⊑ σ ′ . In tal caso T è detto il tipo<br />

principale di t.<br />

Teorema (Soluzione principale): Se (Γ, t, S, C) ha soluzione,<br />

allora ne ha una principale. L’algoritmo di unificazione può<br />

essere usato per determinare se (Γ, t, S, C) ha soluzione e, in<br />

caso positivo, per trovare la principale.<br />

Polimorfismo parametrico – p. 32


Isomorfismo di Curry-Howard<br />

È stato dimostrato che ogni derivazione nel frammento implicazionale<br />

della logica proposizionale intuizionistica corrisponde ad un termine<br />

à la Church (ovvero esplicitamente tipato) tipabile nel λ-<strong>calcolo</strong>.<br />

Polimorfismo parametrico – p. 33


Isomorfismo di Curry-Howard<br />

È stato dimostrato che ogni derivazione nel frammento implicazionale<br />

della logica proposizionale intuizionistica corrisponde ad un termine<br />

à la Church (ovvero esplicitamente tipato) tipabile nel λ-<strong>calcolo</strong>.<br />

Dato che la sintassi delle formule della logica intuizionistica è analoga<br />

a quella della logica del primo ordine, possiamo dedurre, data l’assenza<br />

dei quantificatori, che il sistema di <strong>tipi</strong> basato sui vincoli è un<br />

sottoinsieme dela logica del primo ordine: i <strong>tipi</strong> Nat e Bool sono<br />

costanti, le variabili di tipo sono variabili del <strong>calcolo</strong> e → è un simbolo<br />

funzionale binario.<br />

Polimorfismo parametrico – p. 33


Isomorfismo di Curry-Howard<br />

È stato dimostrato che ogni derivazione nel frammento implicazionale<br />

della logica proposizionale intuizionistica corrisponde ad un termine<br />

à la Church (ovvero esplicitamente tipato) tipabile nel λ-<strong>calcolo</strong>.<br />

Dato che la sintassi delle formule della logica intuizionistica è analoga<br />

a quella della logica del primo ordine, possiamo dedurre, data l’assenza<br />

dei quantificatori, che il sistema di <strong>tipi</strong> basato sui vincoli è un<br />

sottoinsieme dela logica del primo ordine: i <strong>tipi</strong> Nat e Bool sono<br />

costanti, le variabili di tipo sono variabili del <strong>calcolo</strong> e → è un simbolo<br />

funzionale binario.<br />

In questo contesto l’algoritmo di type reconstruction assume il ruolo di<br />

theorem prover.<br />

Polimorfismo parametrico – p. 33


Sistemi formali e typechecking<br />

Per approcciare la semantica formale dei <strong>tipi</strong> è possibile usare modelli<br />

matematici per i <strong>tipi</strong> (mappando ogni espressione di tipo in un insieme<br />

di valori) o definire un sistema formale di assiomi e regole di<br />

inferenza nel quale è possibile provare che un’espressione ha un<br />

qualche tipo. Questi approcci sono complementari: un modello<br />

semantico è spesso una guida nel definire un sistema formale; d’altra<br />

parte ogni sistema formale deve essere self-consistent e questo si<br />

dimostra spesso presentando un modello.<br />

Polimorfismo parametrico – p. 34


Sistemi formali e typechecking<br />

Per approcciare la semantica formale dei <strong>tipi</strong> è possibile usare modelli<br />

matematici per i <strong>tipi</strong> (mappando ogni espressione di tipo in un insieme<br />

di valori) o definire un sistema formale di assiomi e regole di<br />

inferenza nel quale è possibile provare che un’espressione ha un<br />

qualche tipo. Questi approcci sono complementari: un modello<br />

semantico è spesso una guida nel definire un sistema formale; d’altra<br />

parte ogni sistema formale deve essere self-consistent e questo si<br />

dimostra spesso presentando un modello.<br />

Poiché sintattico, il typechecking è collegato più ai sistemi formali che<br />

ai modelli. Un algoritmo di typechecking implementa un sistema<br />

formale, fornendo una procedura per dimostrare teoremi in quel<br />

sistema. Se ha successo nel trovare un tipo per una espressione, allora<br />

tale tipo può essere dedotto dal sistema di inferenza; inoltre è possibile<br />

dedurre l’algoritmo di typechecking a partire dal sistema di inferenza.<br />

Polimorfismo parametrico – p. 34


Un sistema di inferenza<br />

Esistono due distinti modi di vedere il typechecking: uno<br />

consiste nel risolvere un sistema di equazioni di tipo, l’altro<br />

consiste nel provare teoremi in un sistema formale.<br />

Cardelli [2] presenta un sistema di assiomi e regole d’inferenza,<br />

con le quali è possibile ottenere le medesime deduzioni (o<br />

derivazioni) costruite con le regole di typing con vincoli. Qui ne<br />

presentiamo una piccola parte.<br />

Polimorfismo parametrico – p. 35


Un sistema di inferenza<br />

Esistono due distinti modi di vedere il typechecking: uno<br />

consiste nel risolvere un sistema di equazioni di tipo, l’altro<br />

consiste nel provare teoremi in un sistema formale.<br />

Cardelli [2] presenta un sistema di assiomi e regole d’inferenza,<br />

con le quali è possibile ottenere le medesime deduzioni (o<br />

derivazioni) costruite con le regole di typing con vincoli. Qui ne<br />

presentiamo una piccola parte.<br />

Premessa: Indicheremo i <strong>tipi</strong> con lettere minuscole greche e gli<br />

insiemi di assunzioni xi : τi con lettere latine maiuscole.<br />

Un tipo è chiamato shallow (superficiale) se ha la forma<br />

∀α1, ..., ∀αn.τ dove n ≥ 0 senza quantificatori in τ.<br />

Siamo interessati solo ai <strong>tipi</strong> shallow.<br />

Polimorfismo parametrico – p. 35


Un sistema di inferenza<br />

A ⊢ e : τ<br />

A ⊢ e : ∀α.τ<br />

A.x : τ ⊢ x : τ [IDE]<br />

(α non libera in A) [GEN]<br />

A.x : σ ⊢ e : τ<br />

A ⊢ λx.e : σ → τ [ABS]<br />

A ⊢ e : ∀α.τ<br />

A ⊢ e : τ[σ/α]<br />

[SPEC]<br />

Polimorfismo parametrico – p. 36


Un sistema di inferenza<br />

A ⊢ e : τ<br />

A ⊢ e : ∀α.τ<br />

A.x : τ ⊢ x : τ [IDE]<br />

(α non libera in A) [GEN]<br />

A.x : σ ⊢ e : τ<br />

A ⊢ λx.e : σ → τ [ABS]<br />

A ⊢ e : ∀α.τ<br />

A ⊢ e : τ[σ/α]<br />

֒→Esempio: possiamo dedurre il tipo principale per la funzione<br />

identità nel seguente modo:<br />

x : α ⊢ x : α<br />

⊢ λx.x : α → α<br />

⊢ λx.x : ∀α.α → α<br />

[SPEC]<br />

Polimorfismo parametrico – p. 36


Un sistema di inferenza<br />

A ⊢ e : τ<br />

A ⊢ e : ∀α.τ<br />

A.x : τ ⊢ x : τ [IDE]<br />

(α non libera in A) [GEN]<br />

A.x : σ ⊢ e : τ<br />

A ⊢ λx.e : σ → τ [ABS]<br />

A ⊢ e : ∀α.τ<br />

A ⊢ e : τ[σ/α]<br />

֒→Esempio: possiamo dedurre il tipo principale per la funzione<br />

identità nel seguente modo:<br />

x : α ⊢ x : α<br />

⊢ λx.x : α → α<br />

⊢ λx.x : ∀α.α → α<br />

Un tipo specializzato per la funzione identità può essere dedotto da<br />

questo con [SPEC]:<br />

⊢ λx.x : ∀α.α → α<br />

⊢ λx.x : Int → Int<br />

[SPEC]<br />

Polimorfismo parametrico – p. 36


Il costrutto let<br />

Il costrutto let è utile sia per evitare ripetizioni che per aumentare<br />

la leggibilità del codice.<br />

Polimorfismo parametrico – p. 37


Il costrutto let<br />

Il costrutto let è utile sia per evitare ripetizioni che per aumentare<br />

la leggibilità del codice. È aggiunto al λ-<strong>calcolo</strong> aggiungendo<br />

alla sintassi dei termini<br />

e alla semantica<br />

let x = t in t<br />

let x = v1 in t2 → [x ↦→ v1]t2 (E-LETV)<br />

t1 → t ′ 1<br />

let x = t1 in t2 → let x = t ′ 1<br />

in t2<br />

(E-LET)<br />

Polimorfismo parametrico – p. 37


Il costrutto let<br />

Tali aggiunte non rappresentano un’estensione operazionalmente<br />

significativa del linguaggio, infatti let può essere simulato con<br />

una astrazione ed un’applicazione:<br />

let x = t1 in t2 ↔ (λx.t2)t1<br />

Polimorfismo parametrico – p. 38


Il costrutto let ed i <strong>tipi</strong><br />

Per quanto riguarda il sistema dei <strong>tipi</strong> otteniamo però un<br />

linguaggio più espressivo.<br />

֒→ Ad esempio, vorremmo poter tipare Id(Id) ↔ let z = (λx.x) in zz<br />

Polimorfismo parametrico – p. 39


Il costrutto let ed i <strong>tipi</strong><br />

Per quanto riguarda il sistema dei <strong>tipi</strong> otteniamo però un<br />

linguaggio più espressivo.<br />

֒→ Ad esempio, vorremmo poter tipare Id(Id) ↔ let z = (λx.x) in zz ,<br />

ma (λz.zz)(λx.x) non è tipabile.<br />

Polimorfismo parametrico – p. 39


Il costrutto let ed i <strong>tipi</strong><br />

Per quanto riguarda il sistema dei <strong>tipi</strong> otteniamo però un<br />

linguaggio più espressivo.<br />

֒→ Ad esempio, vorremmo poter tipare Id(Id) ↔ let z = (λx.x) in zz ,<br />

ma (λz.zz)(λx.x) non è tipabile. Infatti la sua derivazione è:<br />

z : Z ∈ {z : Z} z : Z ∈ {z : Z}<br />

{z : Z} ⊢ z : Z| ∅{} {z : Z} ⊢ z : Z| ∅{}<br />

{z : Z} ⊢ zz : Y| {Y}{Z = Z → Y}<br />

{} ⊢ λz : Z.zz : Z → Y| {Y}{Z = Z → Y}<br />

L’algoritmo di unificazione incorre in un fallimento per occur check:<br />

Z ∈ Var(Z → Y).<br />

Polimorfismo parametrico – p. 39


Il costrutto let ed i <strong>tipi</strong><br />

Per quanto riguarda il sistema dei <strong>tipi</strong> otteniamo però un<br />

linguaggio più espressivo.<br />

֒→ Ad esempio, vorremmo poter tipare Id(Id) ↔ let z = (λx.x) in zz ,<br />

ma (λz.zz)(λx.x) non è tipabile. Infatti la sua derivazione è:<br />

z : Z ∈ {z : Z} z : Z ∈ {z : Z}<br />

{z : Z} ⊢ z : Z| ∅{} {z : Z} ⊢ z : Z| ∅{}<br />

{z : Z} ⊢ zz : Y| {Y}{Z = Z → Y}<br />

{} ⊢ λz : Z.zz : Z → Y| {Y}{Z = Z → Y}<br />

L’algoritmo di unificazione incorre in un fallimento per occur check:<br />

Z ∈ Var(Z → Y).<br />

Modifichiamo quindi la regola di typing per il let in modo da<br />

eseguire prima del <strong>calcolo</strong> dei <strong>tipi</strong> il passo di valutazione<br />

let x = v1 in t2 → [x ↦→ v1]t2<br />

Polimorfismo parametrico – p. 39


Annotazioni di tipo implicite<br />

Per avere un let polimorfo, innanzitutto aggiungiamo alla sintassi<br />

dei termini la λ-astrazione senza annotazioni di tipo,<br />

associandole la seguente nuova regola di typing:<br />

X /∈ χ Γ, x : X ⊢ t1 : T|χC<br />

Γ ⊢ λx.t1 : X → T|χ∪{X}C<br />

(CT-ABSINF)<br />

Polimorfismo parametrico – p. 40


Il let polimorfo<br />

Adesso aggiungiamo una regola diretta di typing del let:<br />

Γ ⊢ t1 : T1 Γ ⊢ [x ↦→ t1]t2 : T2<br />

Γ ⊢ let x = t1 in t2 : T2<br />

(T-LET)<br />

Abbiamo controllato che anche t1 fosse ben tipato per tutelarci nel caso<br />

in cui x non occorre mai in t2.<br />

La regola per il sistema di vincoli è simile:<br />

Γ ⊢ t1 : T1|χ1C1 Γ ⊢ [x ↦→ t1]t2 : T2|χ2C2<br />

χ1 ∩ χ2 = ∅<br />

Γ ⊢ let x = t1 in t2 : T2|χ1∪χ2{C1 ∪ C2}<br />

(CT-LETPOLY)<br />

Polimorfismo parametrico – p. 41


Nuova type inference<br />

L’uso congiunto di CT-LETPOLY e di CT-ABSINF produce<br />

l’effetto desiderato:<br />

• CT-LETPOLY produce tutte le copie necessarie della<br />

definizione t1 e le sostituisce ovunque il nome x compare<br />

libero in t2;<br />

• la type reconstruction prosegue quindi su questa<br />

espressione espansa, dove con CT-ABSINF si assegna a<br />

ciascuna λ-astrazione una variabile di tipo diversa.<br />

Polimorfismo parametrico – p. 42


Autoapplicazione dell’identità<br />

Le nuove regole introdotte permettono di tipare<br />

l’autoapplicazione dell’identità<br />

La derivazione è la seguente:<br />

x : X ∈ {x : X}<br />

(X fresh)<br />

{x : X} ⊢ x : X| ∅{}<br />

{} ⊢ λx.x : X → X| ∅{}<br />

let z = (λx.x) in zz<br />

x : Y ∈ {x : Y}<br />

(Y fresh)<br />

{x : Y} ⊢ x : Y| ∅{}<br />

x : Z ∈ {x : Z}<br />

(Z fresh)<br />

{x : Z} ⊢ x : Z| ∅{}<br />

{} ⊢ λ x.x : Y → Y| ∅{} {} ⊢ λ x.x : Z → Z| ∅{}<br />

{} ⊢ (λ x.x)(λ x.x) : W| {W}{Y → Y = (Z → Z) → W}<br />

{} ⊢ let z = (λx.x) inzz : W| {W}{Y → Y = (Z → Z) → W}<br />

Polimorfismo parametrico – p. 43


Autoapplicazione dell’identità<br />

L’algoritmo di unificazione esegue i seguenti passi:<br />

unify({Y → Y = (Z → Z) → W})<br />

1. S = Y → Y,T = (Z → Z) → W ⇒<br />

⇒ unify({Y = Z → Z,Y = W})<br />

2. S = Y and Y /∈ Var(Z → Z) ⇒<br />

⇒ unify([Y ↦→ Z → Z]{Y = W}) ◦ [Y ↦→ Z → Z]<br />

⇒ unify({Z → Z = W}) ◦ [Y ↦→ Z → Z]<br />

3. T = W and W /∈ Var(Z → Z) ⇒<br />

⇒ unify([W ↦→ Z → Z]∅) ◦ [W ↦→ Z → Z] ◦ [Y ↦→ Z → Z]<br />

⇒ [] ◦ [W ↦→ Z → Z] ◦ [Y ↦→ Z → Z]<br />

Abbiamo quindi σ = [W ↦→ Z → Z,Y ↦→ Z → Z],<br />

da cui si deduce che il tipo principale è σW = Z → Z.<br />

Polimorfismo parametrico – p. 44


Possibili approfondimenti<br />

1) Le implementazioni pratiche del let-<strong>polimorfi</strong>smo sono<br />

riformulazioni più efficienti: evitano che per ogni occorrenza<br />

della variabile nel corpo del let venga verificato il termine<br />

sostituito.<br />

Polimorfismo parametrico – p. 45


Possibili approfondimenti<br />

1) Le implementazioni pratiche del let-<strong>polimorfi</strong>smo sono<br />

riformulazioni più efficienti: evitano che per ogni occorrenza<br />

della variabile nel corpo del let venga verificato il termine<br />

sostituito.<br />

2) È possibile pensare di astrarre i <strong>tipi</strong> “fuori” dai termini per poi<br />

inserirli in un secondo momento; questo concetto ha portato allo<br />

sviluppo (Girard, 1972; Reynolds, 1974) di una nuova estensione<br />

del λ-<strong>calcolo</strong> con <strong>tipi</strong> semplici, chiamata System F.<br />

Polimorfismo parametrico – p. 45


Possibili approfondimenti<br />

1) Le implementazioni pratiche del let-<strong>polimorfi</strong>smo sono<br />

riformulazioni più efficienti: evitano che per ogni occorrenza<br />

della variabile nel corpo del let venga verificato il termine<br />

sostituito.<br />

2) È possibile pensare di astrarre i <strong>tipi</strong> “fuori” dai termini per poi<br />

inserirli in un secondo momento; questo concetto ha portato allo<br />

sviluppo (Girard, 1972; Reynolds, 1974) di una nuova estensione<br />

del λ-<strong>calcolo</strong> con <strong>tipi</strong> semplici, chiamata System F.<br />

Tale estensione corrisponde, in base all’isomorfismo di<br />

Curry-Howard, alla logica intuizionistica del secondo ordine, la<br />

quale permette quantificazioni sui predicati (ovvero sui <strong>tipi</strong>).<br />

Polimorfismo parametrico – p. 45


Bibliografia<br />

1 Benjamin C.Pierce, Types and Programming Languages -<br />

cap. 22, MIT Press, 2002.<br />

Polimorfismo parametrico – p. 46


Bibliografia<br />

1 Benjamin C.Pierce, Types and Programming Languages -<br />

cap. 22, MIT Press, 2002.<br />

2 Luca Cardelli, Basic Polimorphic Typechecking, AT&T Bel<br />

Laboratories, 1988.<br />

Polimorfismo parametrico – p. 46


FINE<br />

Polimorfismo parametrico – p. 47


FINE<br />

Grazie per l’attenzione<br />

Polimorfismo parametrico – p. 47

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!