Programmazione Funzionale
Introduzione a OCaml
Davide Mottin - Themis Palpanas
March 05, 2014
1/15
OCaml base
Dal lambda-calcolo ad OCaml
I tipi in OCaml
Gli operatori
Creare funzioni
L’inferenza di tipi
Esercizi di inferenza dei tipi
Sommario
2/15
Dal lambda-calcolo ad OCaml
Il lambda-calcolo è il più semplice dei linguaggi funzionali.
Sebbene sia un modello astratto di computazione presenta
numerose analogie con essi. Prendiamo per esempio la funzione
identità.
λ
↓
let id
x .
x
↓ ↓ ↓
x = x; ;
Ossia id è una funzione che valutata su x restituisce x.
OCaml base
3/15
Esercizio
Convertire nella sintassi OCaml le seguenti funzioni
OCaml base
I
square : λx.x 2
I
succ : λx.x + 1
I
comp : λf .λg .λx.(f (g x))
4/15
Esercizio
Convertire nella sintassi OCaml le seguenti funzioni
I
square : λx.x 2
I
succ : λx.x + 1
I
comp : λf .λg .λx.(f (g x))
Soluzione
I
let square x = x*x;;
I
let succ x = x + 1;;
I
let comp f g x = f (g x);;
In realtà la funzione square può essere scritta anche come
let square x = x**2.0;;
usando l’operatore (∗∗) ma in questo caso il tipo diventa
float→float, sapete dirmi il perché?
OCaml base
4/15
Il sistema dei tipi
Come già detto OCaml è un linguaggio a tipizzazione forte e a
scopo statico, ossia viene deciso a tempo di compilazione il tipo
di una determinata espressione
#
#
#
-
2 * 3;;
: int = 6
2.0 *. 3.0;;
: float = 6.
true && false;;
: bool = false
Come funziona? Consideriamo l’espressione 2 ∗ 3;
sostanzialmente l’ambiente OCaml riconosce che 2 e 3 sono int e
che l’operazione ∗ si applica a due int e restituisce un int,
verificata la correttezza viene valutata l’espressione e restituito 6
OCaml base
5/15
Le funzioni di conversione
Data la tipizzazione forte del linguaggio OCaml, esistono una serie
di funzioni di conversione da un tipo ad un altro tutte con la
medesima sintassi.
type1 of type2 : type2→type1
che prende in input un’espressione di tipo type2 e restituisce un
valore di tipo type2. Per esempio int of float prende in input
un float e restituisce un intero. È importante tenere conto della
perdita di precisione, in quanto in questo caso viene restituita LA
SOLA PARTE INTERA del numero e non viene fatto nessun
arrotondamento.
OCaml base
6/15
Le operazioni base (SAQ)
Le operazioni base in OCaml sono implementate come funzioni,
perciò esattamente come qualsiasi altra funzione hanno un tipo
#
#
#
-
(+);;
: int -> int -> int = <fun>
(&&);;
: bool -> bool -> bool = <fun>
(+.);;
: float -> float -> float = <fun>
Addizione tra float e tra int hanno una sintassi diversa perché in
realtà sono nomi di funzione e quindi univoci e non polimorfi.
# 2.0 + 3.0;;
Error: This expression has type float but an expression
was expected of type int
dà un errore di valutazione perché 2.0 e 3.0 sono float applicati
ad una funzione tra int
OCaml base
7/15
Le operazioni base (SAQ) - cont’d
Gli operatori di confronto =, <, >, >=, <> agiscono su tipi
polimorfi ma si aspettano a destra e a sinistra lo stesso tipo.
#
#
-
(<);;
: ’a -> ’a -> bool = <fun>
(=);;
: ’a -> ’a -> bool = <fun>
La funzione
let greaterthan x y = y > x;;
ha quindi tipo α → α → bool
OCaml base
8/15
Esercizio
Per creare operatori personalizzati si può usare la sintassi
let (operator) x y =
expression;;
Creare un’operazione % che calcoli l’ipotenusa di un triangolo
rettangolo. Ricordarsi i tipi corretti.
OCaml base
9/15
Esercizio
Per creare operatori personalizzati si può usare la sintassi
let (operator) x y =
expression;;
Creare un’operazione % che calcoli l’ipotenusa di un triangolo
rettangolo. Ricordarsi i tipi corretti.
Soluzione
let (%) x y = sqrt (x**2.0 +. y**2.0);;
Proviamo a calcolare l’ipotenusa tra
3. % 4.;;
- : float = 5.
equivalente a
(%) 3. 4.;;
- : float = 5.
OCaml base
3.
4. e otterremo
9/15
Esercizi da provare su OCaml
Utilizzando le funzioni square, succ, comp e le operazioni
elementari creare funzioni per calcolare
OCaml base
I
x2 + x2
I
(x + 1)2
I
(x 2 + 1)2
10/15
Esercizi da provare su OCaml
Utilizzando le funzioni square, succ, comp e le operazioni
elementari creare funzioni per calcolare
I
x2 + x2
I
(x + 1)2
I
(x 2 + 1)2
Soluzioni possibili
OCaml base
I
let sumsquare x = square x + square x;;
I
let succsquare x = comp square succ x;;
I
let squaresuccsquare x = comp square (comp succ
square) x;;
10/15
Esercizi da provare su OCaml
Utilizzando le funzioni square, succ, comp e le operazioni
elementari creare funzioni per calcolare
I
x2 + x2
I
(x + 1)2
I
(x 2 + 1)2
Soluzioni possibili
I
let sumsquare x = square x + square x;;
I
let succsquare x = comp square succ x;;
I
let squaresuccsquare x = comp square (comp succ
square) x;;
Esercizio: provare a scrivere x 2 + x 2 usando comp square e (+)
OCaml base
10/15
Coppie e currificazione in OCaml
In OCaml esiste il tipo tupla che ha sintassi (, ...), per chi ha
programmato per molto tempo con linguaggi imperativi le due
funzioni
# let first
val first :
# let first
val first :
(x,y) = x;;
’a * ’b -> ’a = <fun>
x y = x;;
’a -> ’b -> ’a = <fun>
potrebbero sembrare identiche al primo sguardo, in quanto si tende
a pensare che sono funzioni a due parametri, le quali restituiscono
il primo, ma non è proprio cosı̀.
Come per il lambda-calcolo in OCaml NON esistono funzioni a più
parametri, esistono funzioni currificate ad un parametro. Nel
primo caso l’input è una coppia (x,y) tipo α ∗ β, nel secondo caso
l’input è una funzione ad un parametro x di tipo α che restituisce
una funzione di tipo β → α.
Riuscite ad immaginare cosa si può scrivere di diverso dall’una
all’altra?
OCaml base
11/15
Esercizi
OCaml base
I
Scrivere una funzione swap:’a * ’b -> ’b * ’a che
scambi le variabili in una coppia
I
Scrivere una funzione map che applichi una medesima funzione
f ad entrambi i membri di una coppia
I
Utilizzando la funzione precedente scrivere una funzione che
aggiunge 1 ai componenti di una coppia. Qual è il tipo
risultante? Perché?
I
Scrivere la funzione max che restituisce il massimo tra due
numeri.
I
Scrivere una funzione che calcoli l’area del cerchio.
I
Scrivere una funzione che preso in input due cerchi calcoli
l’area dell’anello ottenuto togliendo il cerchio con area minore
al cerchio con area maggiore.
12/15
L’inferenza di tipi
OCaml usa un sistema di inferenza di tipi per stabilire il tipo di
un’espressione, la procedura usata si può riassumere in tre regole:
(1) Assegnazione di un tipo generico a tutte le variabili sconosciute
(2) Inferire attraverso costruttori e operazioni il tipo delle variabili
nel corpo della funzione, ove possibile
(3) Inferire il tipo di ritorno attraverso l’applicazione sistematica
della regola (2)
L’inferenza di tipi
13/15
L’inferenza di tipi
OCaml usa un sistema di inferenza di tipi per stabilire il tipo di
un’espressione, la procedura usata si può riassumere in tre regole:
(1) Assegnazione di un tipo generico a tutte le variabili sconosciute
(2) Inferire attraverso costruttori e operazioni il tipo delle variabili
nel corpo della funzione, ove possibile
(3) Inferire il tipo di ritorno attraverso l’applicazione sistematica
della regola (2)
Esercizio - Inferire il tipo dell’espressione
let f1 g f = (g,f,g f);;
L’inferenza di tipi
13/15
L’inferenza di tipi
OCaml usa un sistema di inferenza di tipi per stabilire il tipo di
un’espressione, la procedura usata si può riassumere in tre regole:
(1) Assegnazione di un tipo generico a tutte le variabili sconosciute
(2) Inferire attraverso costruttori e operazioni il tipo delle variabili
nel corpo della funzione, ove possibile
(3) Inferire il tipo di ritorno attraverso l’applicazione sistematica
della regola (2)
Esercizio - Inferire il tipo dell’espressione
let f1 g f = (g,f,g f);;
(1) Si assegnano tipi generici: g:’b, f:’a
L’inferenza di tipi
13/15
L’inferenza di tipi
OCaml usa un sistema di inferenza di tipi per stabilire il tipo di
un’espressione, la procedura usata si può riassumere in tre regole:
(1) Assegnazione di un tipo generico a tutte le variabili sconosciute
(2) Inferire attraverso costruttori e operazioni il tipo delle variabili
nel corpo della funzione, ove possibile
(3) Inferire il tipo di ritorno attraverso l’applicazione sistematica
della regola (2)
Esercizio - Inferire il tipo dell’espressione
let f1 g f = (g,f,g f);;
(1) Si assegnano tipi generici: g:’b, f:’a
(2) da (g,f,g f) si inferisce che f è applicata a g e quindi se
f:’a, allora g:’a -> ’b
L’inferenza di tipi
13/15
L’inferenza di tipi
OCaml usa un sistema di inferenza di tipi per stabilire il tipo di
un’espressione, la procedura usata si può riassumere in tre regole:
(1) Assegnazione di un tipo generico a tutte le variabili sconosciute
(2) Inferire attraverso costruttori e operazioni il tipo delle variabili
nel corpo della funzione, ove possibile
(3) Inferire il tipo di ritorno attraverso l’applicazione sistematica
della regola (2)
Esercizio - Inferire il tipo dell’espressione
let f1 g f = (g,f,g f);;
(1) Si assegnano tipi generici: g:’b, f:’a
(2) da (g,f,g f) si inferisce che f è applicata a g e quindi se
f:’a, allora g:’a -> ’b
(3) il tipo di ritorno diventa (’a -> ’b) * ’a * ’b
L’inferenza di tipi
13/15
L’inferenza di tipi
OCaml usa un sistema di inferenza di tipi per stabilire il tipo di
un’espressione, la procedura usata si può riassumere in tre regole:
(1) Assegnazione di un tipo generico a tutte le variabili sconosciute
(2) Inferire attraverso costruttori e operazioni il tipo delle variabili
nel corpo della funzione, ove possibile
(3) Inferire il tipo di ritorno attraverso l’applicazione sistematica
della regola (2)
Esercizio - Inferire il tipo dell’espressione
let f1 g f = (g,f,g f);;
(1) Si assegnano tipi generici: g:’b, f:’a
(2) da (g,f,g f) si inferisce che f è applicata a g e quindi se
f:’a, allora g:’a -> ’b
(3) il tipo di ritorno diventa (’a -> ’b) * ’a * ’b
Si conclude f1:(’a -> ’b) -> ’a -> (’a -> ’b) * ’a * ’b
L’inferenza di tipi
13/15
L’inferenza di tipi
L’inferenza di tipi
14/15
Esercizi sull’inferenza di tipi
Determinare il tipo delle seguenti espressioni o scrivere NT se non
tipizzabile. (Esercizi tratti da precedenti esami)
1. let f1 x y = String.length y = x;;
2. let f g x = x +.(g x);;
3. (fun x y -> y x);;
L’inferenza di tipi
15/15
Esercizi sull’inferenza di tipi
Determinare il tipo delle seguenti espressioni o scrivere NT se non
tipizzabile. (Esercizi tratti da precedenti esami)
1. let f1 x y = String.length y = x;;
Soluzione 2
int -> string -> bool
2. let f g x = x +.(g x);;
3. (fun x y -> y x);;
L’inferenza di tipi
15/15
Esercizi sull’inferenza di tipi
Determinare il tipo delle seguenti espressioni o scrivere NT se non
tipizzabile. (Esercizi tratti da precedenti esami)
1. let f1 x y = String.length y = x;;
Soluzione 2
int -> string -> bool
2. let f g x = x +.(g x);;
Soluzione 3
(float -> float) -> float -> float
3. (fun x y -> y x);;
L’inferenza di tipi
15/15
Esercizi sull’inferenza di tipi
Determinare il tipo delle seguenti espressioni o scrivere NT se non
tipizzabile. (Esercizi tratti da precedenti esami)
1. let f1 x y = String.length y = x;;
Soluzione 2
int -> string -> bool
2. let f g x = x +.(g x);;
Soluzione 3
(float -> float) -> float -> float
3. (fun x y -> y x);;
Soluzione 1
’a -> (’a -> ’b) -> ’b
L’inferenza di tipi
15/15