La Programmazione Funzionale (spesso denominata semplicemente PF) è un paradigma di programmazione, oggi sempre più diffuso e utilizzato, le cui radici possono essere fatte risalire al lavoro svolto da Alonzo Church presso il Lambda Calcolo negli anni trenta. Certo, allora le applicazioni non comprendevano lo sviluppo di un linguaggio informatico, per giungere a tale risultato dobbiamo attendere fino agli anni ’50 e al lavoro di Newell, Shaw e Simon presso la RAND Corporation (sviluppo del linguaggio informatico IPL).

Oggi esistono numerosi esempi di linguaggi funzionali, tra questi troviamo il linguaggio Lisp e le sue varianti (Logo, Dylan, ecc), il linguaggio Haskell e gli altri linguaggi appartenenti alla famiglia ML (come OCaml), il linguaggio F# derivato da Microsoft all’interno del framework .NET (tratteremo di F# in questa guida), il linguaggio Scala che viene eseguito sulla JRE (Java Runtime Environment), il linguaggio Erlang e molti altri.

Nel corso di questa breve guida cercherò di illustrare le caratteristiche generali comuni a molti linguaggi funzionali, in generale tuttavia gli esempi proposti saranno codificati usando la notazione del linguaggio OCaml.

Perché si dice funzionale?

Il paradigma di programmazione funzionale è così definito perché il flusso di esecuzione di un programma (codificato mediante uno dei linguaggi precedentemente citati) assume la forma di una serie di valutazioni di funzioni matematiche. Le funzioni dei programmi funzionali non sono paragonabili alle funzioni (o alle procedure) dei linguaggi imperativi (o peggio ancora ad oggetti), esse non svolgono direttive di calcolo bensì si limitano a mappare dei valori in input su dei valori in output.
y = f(x)
f: X \to Y

La funzione f mappa elementi x \in X su elementi y \in Y , nel contesto corrente l’insieme X viene detto dominio, mentre l’insieme Y viene detto codominio. In sintesi diciamo che la funzione f associa ad ogni elemento x \in X uno ed un solo elemento y \in Y .

Confronto con la programmazione imperativa

Se paragonata alla programmazione imperativa può sembrare (specialmente all’inizio) che la programmazione funzionale manchi di molti dei costrutti ritenuti finora essenziali, segnaliamo ad esempio che nella programmazione funzionale non vi è nessuna allocazione di memoria o assegnamento di valore a variabile, vedremo successivamente come questa affermazione non sia in realtà che una semplificazione. D’altro canto l’uso della programmazione funzionale permette l’eliminazione degli effetti collaterali (side-effects) e facilita l’esecuzione dei programmi negli ambienti multi-processore. A differenza della programmazione imperativa, inoltre, la programmazione funzione offre un maggiore distacco dai meccanismi di funzionamento del calcolatore (astrazione), ovviamente questo si traduce anche in un minor controllo sull’ecosistema della macchina.

I programmi scritti con un linguaggio funzionale sono in genere più corti delle controparti scritti con linguaggi imperativi, questo spesso si traduce in programmi più corretti o comunque con meno errori. Inoltre i programmi funzioni sono molto più facili da testare usando tecniche formali o altri sistemi automatici volti garantirne la correttezza (vedremo ad esempio il caso di F# e FsCheck).

Differenze tra i linguaggi funzionali

I linguaggi funzionali non sono tutti uguali, essi vengono suddivisi in due macro-categorie rappresentanti rispettivamente i linguaggi ritenuti “puri” e i linguaggi ritenuti “impuri”, questa suddivisione viene svolta sulla base della loro capacità di permettere o meno degli effetti collaterali, ovvero la possibilità di alterare il loro stato durante l’esecuzione. Un linguaggio funzionale puro non dovrebbe permettere il verificarsi di tali effetti, tuttavia a volte questo non è possibile se non addirittura necessario.