Programmazione funzionale: ideale per gli algoritmi
I comuni linguaggi di programmazione di solito consentono di distinguere tra diversi paradigmi di programmazione, in particolare tra programmazione dichiarativa e imperativa. In parole povere, tali paradigmi sono l’approccio di base nella programmazione di un software. Un sottoinsieme dell’approccio dichiarativo è la cosiddetta programmazione funzionale, che viene utilizzata in particolare nello sviluppo dei seguenti programmi o codici:
- Applicazioni tecniche e matematiche
- Intelligenza Artificiale (IA)
- Compilatori e parser
- Algoritmi
Cosa rende l’approccio dei linguaggi di programmazione funzionali così interessante per questo tipo di applicazioni informatiche? E qual è la differenza rispetto ad altri concetti come la programmazione orientata agli oggetti?
Cos’è la programmazione funzionale?
Come suggerisce il nome, l’approccio funzionale nella programmazione si concentra sulle funzioni. In un programma funzionale, tutti gli elementi possono essere intesi come funzioni e il codice può essere eseguito tramite richieste di funzioni sequenziali. Al contrario, non ci sono assegnazioni autonome di valori. Una funzione può essere considerata come una versione speciale di una subroutine. Questa è riutilizzabile e, a differenza di una procedura, restituisce direttamente il risultato.
Naturalmente, in molti linguaggi di programmazione specializzati ci sono funzioni che vengono definite e poi utilizzate. Non è questo, dunque, il tratto distintivo della programmazione funzionale. Ciò che rende tale approccio così importante per l’informatica e allo stesso tempo così versatile è il fatto che le funzioni possono assumere “strutture” diverse. Ad esempio, possono essere collegate tra loro come dati, utilizzate come parametri e anche come risultati funzionali. Questo trattamento speciale delle funzioni permette ai programmatori di implementare ed elaborare compiti di calcolo di ampia portata (specialmente quelli di natura simbolica).
Perché la programmazione funzionale è così importante oggi
Anche se le radici della programmazione funzionale risalgono agli anni '30 (come parte della ricerca matematica di base), l’approccio funzionale gode ancora di grande popolarità, soprattutto in campo tecnico e matematico. Le ragioni sono molteplici:
- Ampie possibilità di trasformazione del programma algebrico
- Ampie possibilità di sintesi del programma algebrico
- Semplici opzioni di analisi semantica grazie all’eliminazione degli “stati interni nel processo di calcolo” e degli “effetti collaterali”.
- Eliminazione degli stati interni: a differenza della programmazione imperativa, non sono necessari stati interni di un processo di calcolo.
- Nessun effetto collaterale: con il metodo funzionale si possono eliminare anche i cambiamenti di stato appartenenti agli stati interni, cioè i cosiddetti effetti collaterali.
La programmazione funzionale offre un alto grado di astrazione perché si basa sul concetto matematico e sul principio di funzionamento. Se usata adeguatamente, questo tipo di programmazione permette di ottenere un codice molto preciso. Grazie al maggior numero possibile di unità piccole, ripetutamente utilizzabili e molto specializzate, per l’appunto le funzioni, viene fornito un programma per la risoluzione di un compito sostanzialmente più complesso.
Ci sono quindi numerose ragioni pratiche per cui la programmazione funzionale e i relativi linguaggi di programmazione occupano ancora oggi una posizione speciale nell’ambito dell’informatica, specialmente quando si tratta di compiti matematici complessi e algoritmi. Le aree di applicazione molto speciali fanno sì che i linguaggi di programmazione funzionale siano piuttosto di nicchia.
In sintesi: i linguaggi di programmazione funzionale più importanti
Tra i più importanti linguaggi di programmazione basati sull’approccio funzionale vi sono:
- LISP
- ML
- Haskell
- OCaml
- F#
- Erlang
- Clojure
- Scala
Inoltre, ci sono altri noti linguaggi di programmazione che consentono di scegliere la programmazione funzionale tra i diversi paradigmi possibili:
- Perl
- Ruby
- Visual Basic .NET
- Dylan
- ECMAScript
Tabella riassuntiva con vantaggi e svantaggi della programmazione funzionale
Vantaggi | Svantaggi |
---|---|
Programmi stateless | I dati (es. variabili) non possono essere modificati |
Adatto per la parallelizzazione | Recupero di grandi quantità di dati non efficiente |
Codice facilmente testabile | Non consigliato per le connessioni a database e server |
Codice facilmente verificabile, possono essere verificate anche le funzioni stateless | Non adatto a molte ricorsioni dello stesso stack |
Combinabile con la programmazione imperativa, orientata agli oggetti | La programmazione ricorsiva può portare a gravi errori |
Codice più preciso e più breve | Non adatto a tutti i compiti |
La tabella può indicarvi se il paradigma funzionale possa essere o meno l’approccio appropriato per la programmazione di un progetto software. La decisione a favore di uno stile di programmazione dipende spesso dalle preferenze personali dello sviluppatore. Ad esempio, la programmazione orientata agli oggetti come alternativa concreta all’approccio funzionale è molto diffusa tra i programmatori. Di seguito, trovate un confronto tra i due approcci con un esempio pratico conclusivo.
Una tendenza? Programmazione orientata agli oggetti e programmazione funzionale a confronto
Come nel mondo della moda, anche nella programmazione ci sono delle tendenze: da tempo ormai, la programmazione orientata agli oggetti, soprattutto nello sviluppo di applicazioni Web e giochi per computer, è molto popolare. Rispetto alla programmazione funzionale, questo approccio non descrive i singoli elementi come funzioni, ma come oggetti e classi. In combinazione con un sistema di eredità, tutti i componenti possono essere riutilizzati ed estesi in qualsiasi momento e senza problemi. D’altra parte, il codice funzionale è molto più snello, più chiaro e particolarmente vantaggioso quando è necessario un codice testabile e verificabile.
Tra l’altro, in alcuni casi non serve scegliere quale approccio di programmazione adottare: molti linguaggi di programmazione moderni supportano il lavoro con i due paradigmi, in modo che possano essere facilmente combinati e che si possa trarre vantaggio da entrambi.
Programmazione funzionale nell’esempio di un parser
I parser sono elementi centrali in tutti i programmi per computer. Sono spesso indispensabili, poiché traducono il linguaggio di programmazione in linguaggio macchina.
Un parser può essere implementato fondamentalmente sulla base di diversi paradigmi di programmazione, per esempio con un linguaggio orientato agli oggetti. Tuttavia, l’approccio funzionale può offrire una serie di vantaggi utili:
- non esistono variabili globali e mutevoli. Di conseguenza, non ci sono errori di programmazione derivanti dal cosiddetto “mutable global state”, come può essere il caso dei progetti orientati agli oggetti. Un parser ne trae vantaggio in qualità di elemento centrale del programma.
- Grazie alle funzioni di ordine superiore e al codice di programma chiaro, è possibile gestire facilmente anche raccolte di dati più grandi. Questo è molto vantaggioso per un parser, che naturalmente deve elaborare grandi quantità di dati.
- Un parser è un elemento di programma eseguito molto frequentemente. Perciò, è particolarmente necessario che sia programmato con precisione e che funzioni in modo efficiente, come nel caso della programmazione funzionale.
- Un errore nel processo di parsing è solitamente fatale e deve essere evitato il più possibile. Tuttavia, mentre un programma è in esecuzione, sorgono inevitabilmente numerose dipendenze semantiche, che possono portare a gravi errori, spesso solo dopo un tempo di esecuzione più lungo. Una programmazione funzionale correttamente implementata può aiutare a ridurre al minimo o a prevenire completamente questi gravi errori di esecuzione.