È difficile definire esattamente cosa sia un "linguaggio funzionale": al di fuori delle lingue che hai elencato, solo Haskell è puramente funzionale (tutti gli altri adottano una sorta di approccio ibrido). Ci sono alcune caratteristiche del linguaggio che sono molto utili per la programmazione funzionale, e Ruby e Python non ne hanno abbastanza per essere ottimi ambienti per FP. Ecco la mia lista di controllo personale, in ordine di importanza:
- Funzioni e chiusure di prima classe (Ruby, Python e tutti gli altri che hai elencato hanno questo).
- Ottimizzazione di coda chiamata garantita (Erlang, Haskell, Scala e Scheme hanno questo, ma non Python, Ruby o Clojure (ancora)).
- Supporto per l' immutabilità nel linguaggio e nelle librerie standard (questo è un grande che tutti i "linguaggi funzionali" che hai elencato (tranne Scheme) ma Ruby e Python no).
- Supporto a livello di linguaggio per funzioni referenzialmente trasparenti (o pure) (per quanto ne so, solo Haskell lo possiede attualmente).
La necessità di (1) dovrebbe essere ovvia: le funzioni di ordine superiore sono estremamente difficili senza funzioni di prima classe. Quando le persone parlano di Ruby e Python come buone lingue per FP, di solito ne parlano. Tuttavia, questa caratteristica particolare è necessaria ma non sufficiente per rendere un linguaggio buono per FP.
(2) è stata una necessità tradizionale per FP sin da quando è stato inventato Scheme. Senza TCO, è impossibile programmare con una ricorsione profonda, che è uno dei cardini di FP, perché si ottengono overflow dello stack. L'unico linguaggio "funzionale" (per definizione popolare) che non ha questo è Clojure (a causa delle limitazioni della JVM), ma Clojure ha una varietà di hack per simulare il TCO. (Cordiali saluti, Ruby TCO è specifico dell'implementazione , ma Python specificamente non lo supporta .) Il motivo per cui il TCO deve essere garantito è che se si tratta di specifiche implementazioni, le funzioni ricorsive profonde si romperanno con alcune implementazioni, quindi non si può davvero usali affatto.
(3) è un'altra cosa importante che i linguaggi funzionali moderni (in particolare Haskell, Erlang, Clojure e Scala) hanno che Ruby e Python non hanno. Senza entrare troppo nei dettagli, l'immutabilità garantita elimina intere classi di bug, specialmente in situazioni simultanee, e consente cose pulite come strutture di dati persistenti . È molto difficile sfruttare questi vantaggi senza supporto a livello linguistico.
(4) è, per me, la cosa più interessante sui linguaggi puramente funzionali (al contrario dei linguaggi ibridi). Considera la seguente funzione Ruby estremamente semplice:
def add(a, b)
a + b
end
Sembra una funzione pura, ma a causa del sovraccarico dell'operatore, potrebbe mutare entrambi i parametri o causare effetti collaterali come la stampa sulla console. È improbabile che qualcuno sovraccarichi l' +
operatore per avere un effetto collaterale, ma il linguaggio non offre garanzie. (Lo stesso vale per Python, anche se forse non con questo esempio specifico.)
In un linguaggio puramente funzionale, d'altra parte, ci sono garanzie a livello di linguaggio che le funzioni sono referenzialmente trasparenti. Ciò presenta numerosi vantaggi: le funzioni pure possono essere facilmente memorizzate; possono essere facilmente testati senza fare affidamento su alcun tipo di stato globale; e i valori all'interno della funzione possono essere valutati pigramente o in parallelo senza preoccuparsi di problemi di concorrenza. Haskell ne approfitta appieno, ma non ne so abbastanza di altri linguaggi funzionali per sapere se lo fanno.
Detto questo, è possibile utilizzare le tecniche FP in quasi tutte le lingue (anche Java). Ad esempio, MapReduce di Google è ispirato da idee funzionali, ma per quanto ne so non usano linguaggi "funzionali" per i loro grandi progetti (penso che utilizzino principalmente C ++, Java e Python).