Pillole di Haskell - ricerca di duplicati
Di recente ho dovuto scrivere una funzioncina in Haskell per trovare elementi duplicati in una lista. Anche se non necessariamente il più furbo, trovo che il metodo che ho usato fornisca un esempio interessante di programmazione funzionale in questo linguaggio.
L'idea (semplice) è la seguente: ordiniamo la lista (il che richiede che gli elementi siano confrontabili, cioè che appartengano alla classe Ord) e poi cerchiamo due elementi consecutivi uguali. Mostro come implementare quest'idea, procedendo per applicazioni consecutive di funzioni.
Dipendenze esplicite
Uno dei punti di forza dello stile di programmazione funzionale è che la dipendenza della valutazione di una funzione dai suoi parametri è espressa in maniera esplicita. Questo può costituire un peso per lo sviluppatore nella fase di scrittura del codice, ma rappresenta un vantaggio notevole nelle fasi successive di debugging e manutenzione.
Nello stile di programmazione imperativa, può (legittimamente) capitare che un frammento di codice
a = 1; print ( sambucaBottles() ); a = 2; print ( sambucaBottles() );dia per risultato la stampa a schermo di
1 bottiglia di sambuca 2 bottiglie di sambucaAd esempio, questo accadrebbe se a fosse una variabile disponibile alla funzione sambucaBottles e se questa avesse un'implementazione del tipo (in pseudo-code)
Pillole di Haskell - un uso di id
La funzione id (per identity=identità) in Haskell prende il suo argomento e lo restituisce immutato. La sua definizione è
id :: a -> a id x = xid è quindi l'elemento neutro per composizione di funzioni, cioè per ogni f :: a -> b, si ha che
f = f . id = id . f
id non sembra di grande utilità in quanto, di fatto, non fa niente. La sua applicazione a un argomento si può sempre omettere, così come la sua composizione con un'altra funzione. L'unico uso possibile sembrerebbe quello di essere passata come argomento a una funzione di ordine superiore che si aspetti una generica funzione a->a. Chiaramente, nei soli casi in cui passare id abbia senso nella logica del programma.
...MA...
se pure id non ha effetti dal punto di vista computazionale, possiamo utilizzarla per avere vantaggi in fase di compilazione.
Se definiamo una nuova funzione
myid :: A -> A myid = id
dove A è uno specifico tipo di dati (un ADT o un type, anche parzialmente specificati), allora myid forza il tipo dell'argomento, anche nel caso in cui questo sia a priori generico.