Programmazione Funzionale
Transcript
Programmazione Funzionale
Programmazione Funzionale Esercizi sulle liste Davide Mottin - Themis Palpanas April 16, 2014 1/15 Ripasso Costruire una funzione ricorsiva Liste Enumerazione di insiemi Liste strettamente crescenti La funzione map La funzione filter Insieme delle parti Sottoinsiemi di determinata cardinalità Sommario 2/15 Suggerimenti per “pensare” ricorsivo 1. Leggere attentamente il problema da risolvere 2. Pensare al caso più banale nel quale la funzione da costruire sia definita e per il quale possiamo dare il risultato immediatamente (Suggerimento: in molte occasioni il caso base è il minimo di un insieme, se ordinato, per esempio lo 0 per i numeri naturali, [] per le liste, ”” per le stringhe) 3. Pensare a quale valore la funzione assume nel caso ci si trovi di fronte all’input (caso) base, senza preoccuparci delle chiamate ricorsive 4. Pensare al caso ricorsivo in questo modo: 4.1 supporre di sapere risolvere il problema nel caso immediatamente più semplice 4.2 avendo già il risultato del caso semplice costruire il caso più complesso manipolando il risultato della chiamata ricorsiva opportunamente In un certo senso si pensa tutto in maniera bottom-up ossia dal basso verso l’alto. Ripasso 3/15 Suggerimenti per “pensare” ricorsivo Prendiamo per esempio la funzione che conta il numero di elementi in una lista l e t rec l e n g t h = f u n c t i o n [] − > 0 | x : : x s −> 1 + l e n g t h x s ; ; I I Ripasso caso base: la lista più piccola pensabile è la lista vuota, quindi se troviamo [] allora sappiamo PER DEFINIZIONE che la lunghezza di una lista vuota è 0 (nota che non abbiamo avuto bisogno di nessun altra operazione, lo sappiamo senza doverlo calcolare) caso ricorsivo: allora vediamo di estrarre un elemento dalla lista e supponiamo di SAPERE che la funzione length xs restituisce la lunghezza della lista xs, perché un oracolo ci ha detto che lo sappiamo calcolare. Cosa dobbiamo fare per ottenere la lunghezza della lista x::xs dato in input la lunghezza di xs? Banalmente dobbiamo aggiungere 1 perché abbiamo trovato un elemento in più. 4/15 Enumerazione di insiemi Costrure una funzione enumerate:’a list -> (’a * int) list che preso in input una lista costruisca la lista di coppie formate da un elemento della lista in input e da un numero progressivo che rappresenta l’indice di quell’elemento nella lista. Esempio enumerate [’a’;’b’;’c’];; - : (char * int) list = [(’a’, 0); (’b’, 1); (’c’, 2)] Liste 5/15 Enumerazione di insiemi - Soluzione l e t enumerate l = l e t r e c aux c = f u n c t i o n [ ] −> [ ] | x : : x s −> ( x , c ) : : aux ( c +1) x s i n aux 0 l ; ; Liste 6/15 Liste strettamente crescenti Costruire una funzione increasing : ’a list -> ’a list che preso in input una lista di elementi restituisca la lista che rimuove elementi se non sono in ordine crescente Esempio increasing [2;5;3;8;1;2;3];; - : int list = [2; 5; 8] Liste 7/15 Liste strettamente crescenti Costruire una funzione increasing : ’a list -> ’a list che preso in input una lista di elementi restituisca la lista che rimuove elementi se non sono in ordine crescente Esempio increasing [2;5;3;8;1;2;3];; - : int list = [2; 5; 8] Suggerimento 1. Si può pensare di tenere traccia del massimo elemento letto fino a quel punto in una funzione interna. Liste 7/15 Liste strettamente crescenti - Soluzione let increasing = function [ ] −> [ ] | x : : x s −> l e t r e c aux max = f u n c t i o n [ ] −> [ ] | x : : x s −> i f x > max t h e n x : : ( aux x x s ) else aux max x s i n x : : ( aux x x s ) ; ; Liste 8/15 La funzione map La funzione map è una funzione di ordine superiore che presa in input una lista e una funzione generica applica la funzione ad ogni elemento della lista. La sua firma è map: (’a -> ’b) -> ’a list -> ’b list l e t r e c map f = f u n c t i o n [ ] −> [ ] | x : : x s −> ( f x ) : : map f x s ; ; Liste 9/15 La funzione filter Costruire una funzione che “filtri” una lista usando la funzione booleana f in ingresso, ossia che se f è vera aggiunge l’elemento alla lista altrimenti no Liste 10/15 La funzione filter Costruire una funzione che “filtri” una lista usando la funzione booleana f in ingresso, ossia che se f è vera aggiunge l’elemento alla lista altrimenti no Suggerimento 1. La funzione filter non è molto diversa da map, solo che se f applicata ad un argomento è verificata si concatenerà l’elemento alla lista, altrimenti si richiamerà la funzione filter sulla sottolista. Liste 10/15 La funzione filter - Soluzione l e t rec f i l t e r f = f u n c t i o n [ ] −> [ ] | x : : x s −> i f ( f x ) then x : : ( f i l t e r f xs ) e l s e ( f i l t e r f xs ) ; ; Liste 11/15 La funzione filter - Soluzione l e t rec f i l t e r f = f u n c t i o n [ ] −> [ ] | x : : x s −> i f ( f x ) then x : : ( f i l t e r f xs ) e l s e ( f i l t e r f xs ) ; ; E se volessimo costruire una funzione che preso in input una lista di interi restituisca la lista con i soli numeri pari? Liste 11/15 La funzione filter - Soluzione l e t rec f i l t e r f = f u n c t i o n [ ] −> [ ] | x : : x s −> i f ( f x ) then x : : ( f i l t e r f xs ) e l s e ( f i l t e r f xs ) ; ; E se volessimo costruire una funzione che preso in input una lista di interi restituisca la lista con i soli numeri pari? Soluzione. let only even lst = filter (fun x -> x mod 2 = 0) lst;; Liste 11/15 Insieme delle parti Costruire una funzione che calcoli l’insieme delle parti, ossia che dato in input una lista restitusca la lista di tutte le possibili sottoliste. e.g. powerset [1;2] = [[]; [1]; [2]; [1;2]] Liste 12/15 Insieme delle parti Costruire una funzione che calcoli l’insieme delle parti, ossia che dato in input una lista restitusca la lista di tutte le possibili sottoliste. e.g. powerset [1;2] = [[]; [1]; [2]; [1;2]] Hint 1. L’insieme delle parti ha una definizione ricorsiva in quanto lo si può pensare come caso base restituisca una lista di liste vuote (i.e. [[]]) e nel caso ricorsivo come la concatenazione (operatore @) dell’insieme delle parti ottenuto rimuovendo un elemento e la lista di sottoinsiemi ottenuti aggiungendo l’elemento rimosso ad essi Liste 12/15 Insieme delle parti Costruire una funzione che calcoli l’insieme delle parti, ossia che dato in input una lista restitusca la lista di tutte le possibili sottoliste. e.g. powerset [1;2] = [[]; [1]; [2]; [1;2]] Hint 1. L’insieme delle parti ha una definizione ricorsiva in quanto lo si può pensare come caso base restituisca una lista di liste vuote (i.e. [[]]) e nel caso ricorsivo come la concatenazione (operatore @) dell’insieme delle parti ottenuto rimuovendo un elemento e la lista di sottoinsiemi ottenuti aggiungendo l’elemento rimosso ad essi Hint 2. Si può usare la funzione map per aggiungere ad ogni sottolista un elemento, usando la funzione fun l -> x::l Liste 12/15 Insieme delle parti - Soluzione l e t rec powerset = f u n c t i o n [ ] −> [ [ ] ] | x : : x s −> l e t sub = p o w e r s e t x s i n sub @ ( map ( f u n l −> x : : l ) sub ) ; ; Liste 13/15 Sottoinsiemi di cardinalità almeno n Costruire una funzione che rimuova le liste di cardinalità < n dalla dalla liste di tutte le sottoliste Liste 14/15 Sottoinsiemi di cardinalità almeno n Costruire una funzione che rimuova le liste di cardinalità < n dalla dalla liste di tutte le sottoliste Hint 1.Usare le funzioni filter e length Liste 14/15 Sottoinsiemi di cardinalità almeno n - Soluzione l e t r e c remove n l s t = f i l t e r ( f u n l −> ( l e n g t h l ) > n ) ( p o w e r s e t l s t ) ; ; Liste 15/15