Da quanto ho ricavato dall'apprendimento di Haskell, la programmazione funzionale limita la quantità di effetti collaterali, ma in che modo? Spero che qualcuno possa illuminarmi su questo.
Da quanto ho ricavato dall'apprendimento di Haskell, la programmazione funzionale limita la quantità di effetti collaterali, ma in che modo? Spero che qualcuno possa illuminarmi su questo.
Ci sono due diverse definizioni del termine "programmazione funzionale". Ma nessuno dei due limiti ha effetti collaterali.
La definizione originale era "programmazione con subroutine di prima classe e di ordine superiore". Questa era la definizione applicata a LISP, Scheme, ML e molti altri. Al giorno d'oggi, quasi tutte le lingue (ad eccezione di C) hanno subroutine di prim'ordine e di ordine superiore, gli ultimi grandi holdout erano Java e C ++. Quindi, questa definizione è meno utile di una volta, poiché quasi tutte le lingue lo soddisfano.
Quindi, in seguito, divenne popolare una nuova definizione: "programmazione senza effetti collaterali". Questa è la definizione che viene utilizzata in Haskell, per esempio.
Tuttavia, nessuna delle due definizioni limita gli effetti collaterali. La prima definizione non dice nulla sugli effetti collaterali (e all'inizio della LISP e molti dei suoi discendenti, ad esempio CommonLisp sono molto importanti). E la seconda definizione non limita gli effetti collaterali, semplicemente li vieta completamente.
Haskell è una lingua pigra . Un pezzo di codice viene eseguito solo se viene utilizzato il suo valore. Ciò significa che se vogliamo provocare effetti collaterali in una sequenza specifica, dobbiamo modellare l'ordine degli effetti come valore in cui gli effetti successivi richiedono il valore degli effetti precedenti.
In un linguaggio imperativo come C, possiamo semplicemente usare il punto e virgola per le istruzioni di sequenza:
printf("foo");
printf("bar");
In Haskell, per sequenziare gli effetti della stampa di un valore, dobbiamo esprimerlo attraverso il flusso di dati. Qualcosa come:
forceEvaluationInSequence [firstEffect, secondEffect]
where firstEffect = putStr "foo"
secondEffect = putStr "bar"
Questi valori che simboleggiano effetti esterni sono rappresentati in Haskell come monade IO. La funzione main
di un programma restituisce un valore di I / O. L'operatore >>
può essere utilizzato per il sequenziamento tra monadi:
main = putStr "foo" >> putStr "bar"
Poiché le monadi sono fondamentali per Haskell, hanno una sintassi speciale: la notazione. Questo codice è equivalente a quanto sopra:
main = do
putStr "foo"
putStr "bar"
(A causa della somiglianza nella notazione con la programmazione imperativa, le monadi sono talvolta chiamate "punti e virgola programmabili".)
Quindi in Haskell non ci sono più effetti side . Un effetto è modellato esplicitamente come valore. Ciò si allinea bene con l'idea di sostituibilità / ragionamento equo: in un linguaggio puramente funzionale, posso sostituire l'espressione con il valore di tale espressione.
Leggi altre domande sui tag haskell