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