Perché la programmazione funzionale non ha ancora preso il controllo?


197

Ho letto alcuni testi sulla programmazione dichiarativa / funzionale (linguaggi), ho provato Haskell e ne ho scritto uno anch'io. Da quello che ho visto, la programmazione funzionale ha diversi vantaggi rispetto allo stile imperativo classico:

  • Programmi apolidi; Nessun effetto collaterale
  • Concorrenza; Gioca estremamente bene con la crescente tecnologia multi-core
  • I programmi sono generalmente più brevi e in alcuni casi più facili da leggere
  • La produttività aumenta (esempio: Erlang)

  • La programmazione imperativa è un paradigma molto antico (per quanto ne so) e forse non adatto al 21 ° secolo

Perché le aziende che usano o i programmi scritti in linguaggi funzionali sono ancora così "rari"?

Perché, considerando i vantaggi della programmazione funzionale, stiamo ancora usando linguaggi di programmazione imperativi?

Forse era troppo presto per farlo nel 1990, ma oggi?


1
NOTA: questa domanda è stata discussa su meta almeno due volte, e il consenso è che dovrebbe essere mantenuta, sebbene archiviata tramite il blocco di "significato storico" di cui sopra. Incoraggio vivamente chiunque lo veda con un occhio a sbloccarlo per fermarsi e ringraziare per non dover partecipare a un'altra discussione noiosa su questa domanda, godere delle risposte così come sono e andare avanti sulla propria attività.
Shog9,

Risposte:


530

Perché tutti questi vantaggi sono anche svantaggi.

Programmi apolidi; Nessun effetto collaterale

I programmi del mondo reale sono tutti incentrati su effetti collaterali e mutazione. Quando l'utente preme un pulsante è perché vogliono che accada qualcosa. Quando scrivono qualcosa, vogliono che quello stato sostituisca qualunque stato fosse lì. Quando Jane Smith in contabilità si sposa e cambia il suo nome in Jane Jones, il database che sostiene il processo aziendale che stampa la sua busta paga è meglio per gestire quel tipo di mutazione. Quando spari la mitragliatrice contro l'alieno, la maggior parte delle persone non lo modella mentalmente come la costruzione di un nuovo alieno con meno punti ferita; lo modellano come una mutazione delle proprietà di un alieno esistente.

Quando i concetti del linguaggio di programmazione funzionano fondamentalmente contro il dominio da modellare, è difficile giustificare l'uso di quel linguaggio.

Concorrenza; Gioca estremamente bene con la crescente tecnologia multi-core

Il problema è appena stato risolto. Con strutture di dati immutabili hai una sicurezza dei thread economica al costo di lavorare con dati non aggiornati. Con strutture di dati mutabili hai il vantaggio di lavorare sempre su nuovi dati al costo di dover scrivere logiche complicate per mantenere coerenti i dati. Non è che uno di questi sia ovviamente migliore dell'altro.

I programmi sono generalmente più brevi e in alcuni casi più facili da leggere

Tranne nei casi in cui sono più lunghi e più difficili da leggere. Imparare a leggere i programmi scritti in uno stile funzionale è un'abilità difficile; le persone sembrano essere molto meglio nel concepire i programmi come una serie di passaggi da seguire, come una ricetta, piuttosto che come una serie di calcoli da eseguire.

La produttività aumenta (esempio: Erlang)

La produttività deve aumentare molto per giustificare le ingenti spese di assunzione di programmatori che sanno programmare in uno stile funzionale.

E ricorda, non vuoi buttare via un sistema funzionante; la maggior parte dei programmatori non sta costruendo nuovi sistemi da zero, ma piuttosto mantenendo sistemi esistenti, la maggior parte dei quali costruiti in linguaggi non funzionali. Immagina di provare a giustificarlo agli azionisti. Perché hai eliminato il tuo attuale sistema di gestione stipendi per crearne uno nuovo al costo di milioni di dollari? "Perché la programmazione funzionale è fantastica" è improbabile che piaccia agli azionisti.

La programmazione imperativa è un paradigma molto antico (per quanto ne so) e forse non adatto al 21 ° secolo

Anche la programmazione funzionale è molto antica. Non vedo quanto sia rilevante l'età del concetto.

Non fraintendetemi. Adoro la programmazione funzionale, mi sono unito a questo team perché volevo contribuire a portare i concetti della programmazione funzionale in C # e penso che la programmazione in uno stile immutabile sia la strada per il futuro. Ma ci sono costi enormi per la programmazione in uno stile funzionale che non si può semplicemente desiderare. Il passaggio a uno stile più funzionale avverrà lentamente e gradualmente per un periodo di decenni. Ed è quello che sarà: uno spostamento verso uno stile più funzionale, non un abbraccio globale della purezza e della bellezza di Haskell e l'abbandono del C ++.

Costruisco compilatori per vivere e stiamo sicuramente adottando uno stile funzionale per la prossima generazione di strumenti di compilazione. Questo perché la programmazione funzionale è fondamentalmente una buona corrispondenza per il tipo di problemi che affrontiamo. I nostri problemi riguardano il rilevamento di informazioni non elaborate - stringhe e metadati - e la loro trasformazione in stringhe e metadati diversi. In situazioni in cui si verificano mutazioni, come qualcuno sta digitando nell'IDE, lo spazio problematico si presta intrinsecamente a tecniche funzionali come la ricostruzione incrementale delle sole parti dell'albero che sono cambiate. Molti domini non hanno queste belle proprietà che li rendono ovviamente suscettibili di uno stile funzionale .


41
"Quando Jane Smith in contabilità si sposa e cambia il suo nome in Jane Jones, il database che sostiene il processo aziendale che stampa la sua busta paga è meglio per gestire quel tipo di mutazione." Ci sarà un record dell'ex nome di Jane Smith, non aggiorniamo retroattivamente tutte le istanze dell'ex nome di Jane con il suo nuovo nome;)
Juliet

40
@Juliet: Sicuro. Il mio punto è che se si dispone di un oggetto che rappresenta un dipendente, ha senso pensare all'operazione "cambia il nome dell'impiegato" come una mutazione dell'oggetto che rappresenta l'impiegato che non cambia l'identità dell'oggetto . Quando Jane Smith cambia nome, non crei un altro dipendente chiamato Jane Jones, che è altrimenti lo stesso. Non ci sono due impiegati con due nomi diversi. È naturale modellare questo processo come una mutazione di un oggetto, non come la costruzione di un nuovo oggetto.
Eric Lippert,

24
Questa è una buona risposta, ma a volte penso che tu abbia sopravvalutato il tuo caso. Come ha detto Juliet, anche se la gente potrebbe pensarlo come un cambio di nome, in realtà è un sostituto del nome a un livello più profondo. E anche se i programmi funzionali potrebbero essere più difficili da leggere per le persone (perché è un'abilità appresa), non è generalmente perché sono più lunghi. Un programma Haskell sarà quasi sempre più conciso rispetto, per esempio, a un programma Java, anche in un dominio "non adatto" con un sacco di stato intrinseco.
Chuck,

29
+1 È stata una tale boccata d'aria fresca per leggere questa risposta. Fantastico ascoltare tale pragmatismo (con una passione di fondo per la programmazione funzionale) da qualcuno nella tua posizione.
Dhaust

11
"Perché tutti questi vantaggi sono anche svantaggi. Programmi senza stato; nessun effetto collaterale": per quanto ho capito (non ne so abbastanza di FP per scrivere una risposta autorevole) questo non è corretto . La programmazione funzionale riguarda la trasparenza referenziale e non l'evitamento dello stato (anche se lo stato deve essere gestito in modo appropriato per garantire la trasparenza referenziale). Haskell consente lo stato e la mutazione. Fornisce solo strumenti diversi (si potrebbe dire, meglio) per ragionare al riguardo.
Giorgio,

38

Menti della programmazione: conversazioni con i creatori dei principali linguaggi di programmazione

[Haskell]

Perché pensi che nessun linguaggio di programmazione funzionale sia entrato nel mainstream?

John Hughes: marketing scadente! Non intendo propaganda; ne abbiamo avuto un sacco. Intendo una scelta attenta di una nicchia di mercato target da dominare, seguita da uno sforzo deciso per rendere la programmazione funzionale di gran lunga il modo più efficace per affrontare quella nicchia. Nei giorni felici degli anni '80, pensavamo che la programmazione funzionale fosse buona per tutto - ma definire la nuova tecnologia "buono per tutto" equivale a chiamarlo "particolarmente bravo a nulla". Come dovrebbe essere il marchio? Questo è un problema che John Launchbury ha descritto molto chiaramente nel suo discorso invitato all'ICFP. Galois Connections era quasi fallito quando il loro marchio era "software in linguaggi funzionali", ma sono passati sempre più da quando si sono concentrati sul "software ad alta affidabilità".

Molte persone non hanno idea di come avvenga l'innovazione tecnologica e si aspettano che una tecnologia migliore diventerà semplicemente dominante da sola (l' effetto "migliore trappola per topi" ), ma il mondo non è proprio così.


36
Haskell: dopo 20 anni, un successo dall'oggi al domani!
Juliet,

segui il link e leggi le recensioni per un dis piuttosto divertente di Grady Booch. Non ho idea di chi sia Booch, ma mi ha fatto lol comunque.
fearofawhackplanet

4
Grady Booch è responsabile, in definitiva, insieme a Jacobson e Rumbaugh, per l'abominio che è UML.
SOLO IL MIO OPINIONE corretta,

27

La risposta dello stock è che nessuno dei due sostituirà o dovrebbe sostituire l'altro - sono strumenti diversi che hanno diversi insiemi di pro e contro e che l'approccio ha il vantaggio differirà a seconda del progetto e di altri problemi "soft" come il pool di talenti disponibili.

Penso che tu abbia ragione che la crescita della concorrenza dovuta al multi-core aumenterà la percentuale (dell'insieme globale di progetti di sviluppo) quando la programmazione funzionale viene scelta rispetto ad altri stili.

Penso che sia raro oggi perché la maggior parte del pool di talenti professionali di oggi è più a suo agio con le tecnologie imperative e orientate agli oggetti. Ad esempio, ho scelto più volte Java come lingua per un progetto commerciale perché era abbastanza buono, non controverso, e so che non finirò mai le persone che possono programmare (abbastanza bene) in esso.


Questo è molto penetrante e deliziosamente pragmatico. Sicuramente la migliore risposta che ho visto a questa domanda in tutte le sue forme.
Benson,

Forse con una lingua per la quale entrambi sono cittadini di prima classe diventeranno popolari.
Kevin Kostlan,

1
Accetto 110%. In diverse occasioni, ho provato ad entrare in FP, ma ho perso la voglia di continuare dopo alcune settimane. Sto programmando proceduralmente da oltre 30 anni e sono troppo abituato alla programmazione imperativa. Questo è vero per il settore IT in generale. Il cambiamento non arriverà facilmente né rapidamente.
Richard Eng,

26

Nonostante i vantaggi della programmazione funzionale, la programmazione imperativa e orientata agli oggetti non scomparirà mai completamente.

La programmazione imperativa e orientata agli oggetti è una descrizione dettagliata del problema e della sua soluzione. Come tale, può essere più facile da capire. La programmazione funzionale può essere un po 'oscura.

In definitiva, un programma utile avrà sempre effetti collaterali (come fornire all'utente un output effettivo per il consumo), quindi i linguaggi funzionali più puri avranno ancora bisogno di un modo per entrare nel mondo imperativo di volta in volta.

L'attuale stato dell'arte è che le lingue imperative (come C #) prendono in prestito funzionalità dal mondo funzionale (come le dichiarazioni lambda) e viceversa.


3
OOP non è forse una sorta di sottoinsieme della programmazione imperativa?
pankrax,

9
OOP è un superset. OOP è imperativo come C ++ lo è per C.
Robert Harvey,

10
Non penso che OOP faccia necessariamente affidamento sulla programmazione imperativa. Guarda un Clojure o CLOS - entrambi sono funzionali, ma orientati agli oggetti.
Gabe,

9
Le lingue OO tendono ad essere imperative, ma non devono esserlo. OCaml è un linguaggio fortemente funzionale (anche se non puramente) la cui intera ragion d'essere è OO.
Chuck,

7
Non capisco perché OOP sia un superset di programmazione imperativa. Non tutto il codice imperativo è OOP e non tutto il codice funzionale è non OOP. Preferirei dire che OOP è per la programmazione imperativa e la programmazione funzionale come le ali aerodinamiche sono per auto da corsa, o aerei, o razzi, ventole di raffreddamento, o mulini a vento, o ... vale a dire, i concetti sono correlati, ma non strettamente associati una connessione 1 a 1.
Sebastian Mach,

21

No?

Smalltalk era un grande sistema orientato agli oggetti nel passato. Perché la programmazione orientata agli oggetti non è subentrata? Bene, l'ha fatto. Semplicemente non sembra Smalltalk. Le lingue tradizionali continuano a diventare più simili a Smalltalk con C ++, Java, C #, ecc. La moda e lo stile cambiano più lentamente di ogni altra cosa, quindi quando OO divenne mainstream, lo ottenemmo incollando parti di OO su vecchie lingue in modo che sembrasse abbastanza C da ingoiare .

Funzionale è allo stesso modo. Haskell era un grande linguaggio funzionale. Ma oggi abbiamo ancora più massa di programmatori mainstream che usano la sintassi di tipo C rispetto a 20 anni fa. Quindi deve sembrare C. Fatto: guarda qualsiasi espressione LINQ e dimmi che non è funzionale.


2
Punto interessante, ma in che modo le lingue tradizionali stanno diventando più simili a Smalltalk? C ++, Java e C #, ad esempio, non si basano sull'invio di messaggi, che (credo) sia la parte più importante del paradigma Smalltalk.
Jonathan Sterling,

4
Jonathan: scegli qualsiasi funzionalità Smalltalk e osserva come è più debole in C ++ (il più vecchio), OK in Java e meglio in C #. Ad esempio, GC (solo Java / C #), box automatico (solo in seguito Java / C #), chiusure (solo C #) e reflection (presente in Java, meglio in C #). Se vuoi passare messaggi, guarda C # 4 dynamic. Questa è la più piccola di queste funzionalità, quindi non mi sorprende che sia presente solo nell'ultima versione della più moderna di queste tre lingue. :-)
Ken

Javascript, python e ruby ​​sono buone illustrazioni di come ha effettivamente fatto
nafg

15

Credo che le lingue imperative siano più diffuse semplicemente perché è ciò a cui sono abituate più persone. Né la programmazione funzionale né il modello di programmazione imperativa sono più oscuri o accademici dell'altro. In realtà, sono complementi.

Un poster diceva che il codice imperativo è più facile da capire rispetto al codice di programmazione funzionale. Questo è vero solo se il lettore ha già visto un codice imperativo, specialmente se gli esempi precedenti fanno parte della stessa "famiglia" (ad esempio, C / C ++, Perl, PHP e Java). Non direi che è vero per nessuno linguaggio imperativo; fare un confronto tra Java e Forth, per fare un esempio estremo.

Per un laico, tutti i linguaggi di programmazione sono incomprensibili senza senso, tranne forse i linguaggi verbosi come Hypertalk e SQL. (Da notare, SQL è un linguaggio dichiarativo e / o funzionale e gode di enorme popolarità.)

Se fossimo stati inizialmente formati su un linguaggio Lisp-y o Haskell-y dall'inizio, tutti penseremmo che i linguaggi di programmazione funzionale siano perfettamente normali.


"Un poster ha affermato che il codice imperativo è più facile da comprendere rispetto al codice di programmazione funzionale. Questo è vero solo se il lettore ha già visto il codice imperativo, soprattutto se gli esempi precedenti fanno parte della stessa" famiglia "(ad esempio C / C ++, Perl, PHP e Java). ": Molto vero (+1): Ricordo quanti sforzi ho dovuto fare per imparare Pascal e C quando ho iniziato a programmare. E quanto è facile leggere Scala, Haskell o Scheme ora che ho una certa esperienza con queste lingue.
Giorgio,

2
L'unico motivo per cui considero ancora utile lo stato mutevole a volte è che offre un modo semplice per scrivere codice veloce (nessuna copia); ma la ragione potrebbe essere che non conosco abbastanza programmazione funzionale e che, per il 90% delle situazioni, è possibile scrivere codice funzionale veloce senza usare lo stato mutabile.
Giorgio,

3
Uno degli ambienti più utilizzati e di lunga durata per l'organizzazione del calcolo è il foglio di calcolo; essenzialmente un ambiente di programmazione funzionale con celle anziché variabili con nome. Non credo che le persone, in generale, concepiscano intrinsecamente i programmi come una serie di passaggi. Forse i programmatori erano intrisi di diffuse lingue imperative.
jpnp,

14

Hai già ricevuto abbastanza risposte che menzionerò solo un paio di cose che non vedo ancora menzionate.

Innanzitutto e (nella mia mente) soprattutto, i linguaggi procedurali hanno tratto grande beneficio dal loro grado di comunanza. Ad esempio, quasi tutti quelli che conoscono quasi tutti i principali linguaggi procedurali (o OO) in quasi tutti grado possono leggere la maggior parte degli altri ragionevolmente bene. Evito attivamente di lavorare in Java, C #, Cobol, Fortran o Basic (solo per alcuni esempi), ma riesco a leggerne uno abbastanza ragionevole - quasi altrettanto, in effetti, come le persone che li usano ogni giorno.

Dal punto di vista funzionale, questo è molto meno vero. Ad esempio, posso anche scrivere Scheme abbastanza ragionevolmente, ma è di scarsa utilità nella lettura di Ocaml o Haskell (solo per un paio di esempi). Anche all'interno di una singola famiglia (ad esempio, Scheme vs., Common Lisp) la familiarità con l'una non sembra tradursi altrettanto bene nell'altra.

L'affermazione che il codice funzionale è più leggibile tende ad essere vera solo in un ristretto intervallo di condizioni. Per le persone che hanno un'estrema familiarità con la lingua, la leggibilità è davvero eccellente, ma per tutti gli altri è spesso quasi inesistente. Peggio ancora, mentre le differenze nei linguaggi procedurali sono in gran parte sintattiche e quindi relativamente facilmente apprese, le differenze nei linguaggi funzionali sono spesso molto più fondamentali, quindi richiedono uno studio considerevole per capire veramente (ad esempio, sapere che Lisp è di scarso aiuto nella comprensione delle Monadi).

L'altro punto importante è che l'idea che i programmi funzionali siano più brevi di quelli procedurali si basa spesso più sulla sintassi che sulla semantica. I programmi scritti in Haskell (per un esempio) sono spesso piuttosto brevi, ma il suo essere funzionale è una parte piuttosto piccola di ciò. Molto se è semplicemente che Haskell ha una sintassi relativamente concisa.

Pochi linguaggi puramente funzionali possono competere bene con APL per il codice sorgente abbreviato (anche se, in tutta onestà, APL supporta anche la creazione di funzioni di livello superiore, quindi non è una grande differenza come in alcuni altri casi). Al contrario, Ada e C ++ (solo per un paio di esempi) possono essere abbastanza competitivi in ​​termini di numero di operazioni necessarie per svolgere un determinato compito, ma la sintassi è (almeno di solito) sostanzialmente più dettagliata.


Ottimo commento! Sono d'accordo con tutto il cuore. Trovo che la maggior parte dei linguaggi procedurali sia abbastanza facile da leggere e comprendere, anche se sono solo un esperto in buona fede in un paio di essi. Non posso dire lo stesso delle lingue FP.
Richard Eng,

1
Un altro punto importante è che, in ogni dato paradigma, trovi una vasta gamma di competenze, dai neofiti ai guru. Il codice FP può essere facilmente leggibile e comprensibile per gli esperti, ma i programmatori mediocri possono ancora avere difficoltà. Gli esperti di solito comprendono una frazione molto piccola della comunità FP.
Richard Eng,

11

Nessun bisogno percepito

Ricordo la risposta del mio vecchio capo Rick Cline quando gli mostrai una copia della conferenza del Turing Award di John Backus intitolata Can Programming Be Liberated from the von Neumann Style?

La sua risposta: "Forse alcuni di noi non vogliono essere liberati dallo stile di von Neumann!"


10

Perché la programmazione funzionale non ha ancora preso il controllo?

Funzionale è meglio per alcune cose e peggio per altre, quindi non "prenderà il controllo". Tuttavia, è già onnipresente nel mondo reale.

Programmi apolidi; Nessun effetto collaterale

I programmi senza stato sono più facili da testare. Questo è ora ampiamente apprezzato e spesso sfruttato nell'industria.

Concorrenza; Gioca estremamente bene con la crescente tecnologia multi-core I programmi sono generalmente più brevi e in alcuni casi più facili da leggere La produttività aumenta (esempio: Erlang)

Stai mescolando contemporaneamente e parallelismo.

La concorrenza può essere effettuata in modo efficace utilizzando i processi sequenziali comunicanti (CSP). Il codice all'interno di un CSP può mutare il suo stato locale ma i messaggi inviati tra loro dovrebbero essere sempre immutabili.

La programmazione puramente funzionale gioca estremamente male con il multicore perché è così ostile alla cache. I core si contendono la memoria condivisa e i programmi paralleli non si ridimensionano.

Perché le aziende che usano o i programmi scritti in linguaggi funzionali sono ancora così "rari"?

Scala è spesso considerato un linguaggio funzionale, ma non è più funzionale di C #, che è una delle lingue più popolari al mondo oggi.

Perché, considerando i vantaggi della programmazione funzionale, stiamo ancora usando linguaggi di programmazione imperativi?

La programmazione puramente funzionale presenta molti seri svantaggi, quindi utilizziamo linguaggi funzionali impuri come Lisp, Scheme, SML, OCaml, Scala e C #.


7

Quando penso a quale programmazione funzionale potrebbe portare ai miei progetti sul lavoro, sono sempre guidato sullo stesso percorso del pensiero:

  1. Per ottenere tutti i vantaggi della programmazione funzionale è necessaria la pigrizia. Sì, ci sono linguaggi funzionali rigorosi, ma i reali vantaggi della programmazione funzionale non risplendono altrettanto nel codice rigoroso. Ad esempio, in Haskell è facile creare una sequenza di operazioni pigre in un elenco e concatenarle e applicarle a un elenco. Per esempio. op1 $ op2 $ op3 $ op4 $ someList. So che non costruirà l'intero elenco e internamente avrò solo un bel ciclo che attraversa gli elementi uno alla volta. Questo ti permette di scrivere un codice davvero modulare. L'interfaccia tra due moduli può comportare la consegna di strutture dati potenzialmente vaste, e tuttavia non è necessario che la struttura sia residente.

  2. Ma quando hai la pigrizia, diventa difficile ragionare sull'uso della memoria. La modifica dei flag del compilatore Haskell spesso modifica la quantità di memoria utilizzata da un algoritmo da O (N) a O (1), tranne che a volte no. Questo non è davvero accettabile quando si hanno applicazioni che devono sfruttare al massimo tutta la memoria disponibile e non è eccezionale nemmeno per le applicazioni che non richiedono tutta la memoria.


La pigrizia interagisce anche in modo non ideale con il debug.
Brian,

3
Poiché scopro che molti dei bug che inseguo in altre lingue sono legati alla mancanza di trasparenza referenziale, sono meno preoccupato per i problemi di debug, anche se a volte possono essere una seccatura.
sigfpe,

6

Due cose:

  1. Ci vuole solo tempo, non importa quanto sia buona una tecnologia. Le idee alla base di FP hanno circa 70 anni. Ma il suo uso principale nell'ingegneria del software (nelle trincee, nell'industria) è probabilmente inferiore a 10 anni. Chiedere agli sviluppatori di adottare nuove mentalità razzialmente è possibile, ma richiede solo tempo (molti, molti anni). Ad esempio, nei primi anni '80 OOP ottenne davvero un uso mainstream. Tuttavia, non ha ottenuto la dormienza fino alla fine degli anni '90.
  2. Hai bisogno che le persone siano costrette ad affrontare la forza di una tecnologia prima che colpisca in grande . Attualmente, le persone usano strumenti che non fanno uso del parallelismo e le cose funzionano bene. Quando le app che non usano il parallelismo diventano insopportabilmente lente; allora molte persone saranno costrette a usare strumenti di parallelismo e FP potrebbe aumentare in popolarità. Ciò può valere anche per gli altri punti di forza di FP.

3
FP è molto bravo nel riutilizzo del codice. Probabilmente meglio di OO. Ho dovuto occuparmene alcune volte al lavoro, migrando a diversi tipi e un nuovo sistema ed era indolore.
nlucaroni,

@Freddy Rios e @nlucaroni. Ho riformulato il commento per chiarire l'interpretazione errata.
Phil
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.