Negli ultimi tempi stiamo assistendo ad un crescente interesse verso la programmazione funzionale. Linguaggi di programmazione come Elm,Erlang, Clojure o Haskell stanno attirando sempre più l'attenzione di numerosi sviluppatori ed il numero di progetti scritti in questi linguaggi è in crescita. La sempre maggiore popolarità dei linguaggi di programmazione funzionale sta anche influenzando i cosiddetti linguaggi tradizionali. Da qualche anno, infatti, si è visto un generale arricchimento del supporto di caratteristiche funzionali all'interno di linguaggi non funzionali come Java e C#. Ci riferiamo, per fare qualche esempio, all'introduzione delle lambda expression e al supporto delle closure, al diffondersi di librerie dichiarative per la manipolazione di liste (es.: LINQ) e per il supporto dell'immutabilità dei dati, ecc.
C'è da dire che la programmazione funzionale non è una novità di questi ultimi tempi. La sua prima introduzione risale agli studi sul lambda calcolo, un sistema formale proposto da Alonzo Church intorno alla metà degli anni '30 come modello computazionale che ha ispirato la semantica del LISP, linguaggio di programmazione funzionale ideato verso la fine degli anni '50.
Per diversi decenni la programmazione funzionale è stata per certi versi dimenticata (o usata limitatamente all'ambito accademico), lasciando il passo al paradigma di programmazione che la maggior parte degli sviluppatori conosce: quello imperativo, anche se camuffato coi panni della programmazione orientata agli oggetti.
La programmazione funzionale
Ma che cos'è esattamente la programmazione funzionale? Che vantaggi offre rispetto alla programmazione tradizionale?
Da un punto di vista puramente teorico, la programmazione funzionale prende il concetto di funzione matematica come elemento di base del calcolo.
Una funzione matematica è una relazione tra insiemi che associa ad uno
o più elementi di un insieme, detto dominio, uno e un solo elemento di
un altro insieme, detto codominio.
In genere si dice che l'elemento del codominio è il risultato dell'applicazione della funzione sugli elementi del dominio. L'aspetto interessante delle funzioni matematiche è che, a parità di elementi del dominio, l'applicazione di una funzione restituisce sempre lo stesso risultato. In altre parole, l'applicazione di una funzione matematica è deterministica e pertanto è possibile fare verifiche di correttezza ed altre elaborazioni formali.
Questo è uno dei vantaggi fondamentali della programmazione funzionale rispetto alla programmazione imperativa. Infatti, nella programmazione tradizionale l'applicazione di una funzione può in certi casi restituire risultati diversi a parità di valori di input. Questo accade quando la funzione fa riferimento ad uno stato, condiviso o meno, e questo viene modificato da effetti collaterali derivanti dall'esecuzione della funzione stessa o di altre entità. Avremo modo di tornare su questi concetti nel corso della guida. Per il momento ci basta evidenziare i seguenti punti caratterizzanti della programmazione funzionale:
- le funzioni sono funzioni matematiche che per un dato input restituiscono sempre lo stesso risultato;
- le funzioni non modificano i dati ricevuti in input, ma restituiscono sempre nuovi valori;
- le funzioni possono essere passate come parametro e restituite da altre funzioni, e possono essere combinate tra di loro.
Questi semplici punti possono essere considerati i punti fondamentali della programmazione funzionale e da essi derivano altre caratteristiche. Ovviamente esistono altri aspetti tipicamente supportati dai linguaggi di programmazione funzionale, ma il nostro obiettivo in questa guida è comprendere quali sono i principi fondamentali di questo modello di programmazione, e come possiamo applicarli quando scriviamo codice in JavaScript.
È importante evidenziare che la programmazione funzionale è un paradigma di programmazione, cioè un modo di vedere la programmazione, un approccio, un modello per la costruzione di programmi. Come tale quindi non è legato ad uno specifico linguaggio di programmazione. Naturalmente, un linguaggio di programmazione specificamente progettato per la programmazione funzionale ci indirizza all'applicazione dei principi di questo paradigma e ci impedisce di commettere errori grossolani che violano i principi di base. Con un linguaggio non funzionale dobbiamo essere noi ad imporci una disciplina nella scrittura di codice che rispetti i principi di base del paradigma funzionale. E questo non sempre risulta così semplice, soprattutto se non è chiaro il modello proposto e se continuiamo a pensare con un approccio imperativo.
JavaScript è un linguaggio funzionale?
Nel suo articolo "JavaScript: The World's Most Misunderstood Progranning Language", Douglas Crockford definiva JavaScript come "Lisp in C's clothing", ovvero Lisp travestito da C. Egli sosteneva che JavaScript ha più cose in comune con i linguaggi funzionali che con C o Java. In effetti, quando è stato pubblicato l'articolo (2001) JavaScript aveva già quelle caratteristiche funzionali che sono poi state aggiunte anche ad altri linguaggi imperativi. Ad esempio, così come nel modello funzionale, anche in JavaScript le funzioni sono protagoniste: sono costruttori di oggetti, possono essere passate ad altre funzioni, possono essere restituite da funzioni, possiamo comporle e creare espressioni. Possiamo affermare che JavaScript è un linguaggio funzionale?
A rigore, non possiamo dire che JavaScript sia un puro linguaggio funzionale. Esso non ha i meccanismi che ci costringono a seguire determinate modalità di programmazione e ci impediscono di commettere errori che violano il modello funzionale. Ciò nonostante possiamo adottare alcune pratiche che ci consentono di scrivere codice secondo un approccio funzionale e godere pertanto dei relativi vantaggi di flessibilità e testabilità.
Nel corso di questa guida vedremo come applicare le principali tecniche di programmazione funzionale e scopriremo alcune caratteristiche del linguaggio che semplificano l'adozione dell'approccio funzionale e ci consentono di vedere la programmazione sotto un altro punto di vista.