# posso definire le coppie polimorfe (con elementi dello stesso tipo) - type 'a pair = 'a * 'a; > type 'a pair = 'a * 'a # osservare che i tipi 'a pair e 'a * 'a sono compatibili: - fun fst (x:'a pair) = let val (f,s)=x in f end; > val 'a fst = fn : 'a * 'a -> 'a # altrimenti la funzione fst funziona anche su coppie eterogenee: - fun fst x = let val (f,s)=x in f end; > val ('a, 'b) fst = fn : 'a * 'b -> 'a # posso anche applicare un tipo generico a un tipo - type boolpair = bool pair; > type boolpair = bool * bool # oppure costruire le coppie di funzioni: - type ('a,'b) funpair = ('a->'b) pair; > type ('a, 'b) funpair = ('a -> 'b) * ('a -> 'b) # posso definire tipi semplicemente specificando un insieme # di COSTRUTTORI con relativi tipi: - datatype nani = Brontolo | Cucciolo | Dotto | Eolo | Gongolo | Mammolo | Pisolo; > New type names: =nani datatype nani = (nani, {con Brontolo : nani, con Cucciolo : nani, con Dotto : nani, con Eolo : nani, con Gongolo : nani, con Mammolo : nani, con Pisolo : nani}) con Brontolo = Brontolo : nani con Cucciolo = Cucciolo : nani con Dotto = Dotto : nani con Eolo = Eolo : nani con Gongolo = Gongolo : nani con Mammolo = Mammolo : nani con Pisolo = Pisolo : nani # e poi definire funzioni per pattern matching: - fun altezza Brontolo = 125 | altezza Cucciolo = 85 | altezza x = 100; > val altezza = fn : nani -> int - altezza Eolo; > val it = 100 : int # piu' interessante: tipi induttivi come i naturali: - datatype nat = zero | succ of nat; > New type names: =nat datatype nat = (nat,{con succ : nat -> nat, con zero : nat}) con succ = fn : nat -> nat con zero = zero : nat # e funzione per ricorsione strutturale: - fun somma n zero = n | somma n (succ m) = succ (somma n m); > val somma = fn : nat -> nat -> nat - val uno = succ zero; > val uno = succ zero : nat - val due = succ uno; > val due = succ(succ zero) : nat - val tre = somma uno due; > val tre = succ(succ(succ zero)) : nat # e via via funzioni piu' complesse: - fun prodotto n zero = zero | prodotto n (succ m) = somma n (prodotto n m); > val prodotto = fn : nat -> nat -> nat - prodotto due tre; > val it = succ(succ(succ(succ(succ(succ zero))))) : nat # ecco le liste di interi: - datatype intlist = null | add of int * intlist; > New type names: =intlist datatype intlist = (intlist,{con add : int * intlist -> intlist, con null : intlist}) con add = fn : int * intlist -> intlist con null = null : intlist # ma anche le liste generiche (osservare l'astrazione sul tipo # all'inizio: - datatype ('a) myList = empty | cons of 'a * 'a myList; > New type names: =myList datatype 'a myList = ('a myList, {con 'a cons : 'a * 'a myList -> 'a myList, con 'a empty : 'a myList}) con 'a cons = fn : 'a * 'a myList -> 'a myList con 'a empty = empty : 'a myList # ecco le funzioni per ricorsione: - fun length empty = 0 | length (cons(h,t)) = 1 + length(t); > val 'a length = fn : 'a myList -> int - val l = cons ( 2, cons (3, empty)); > val l = cons(2, cons(3, empty)) : int myList - length l; > val it = 2 : int