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