Perché gli effetti collaterali sono considerati malvagi nella programmazione funzionale?


69

Sento che gli effetti collaterali sono un fenomeno naturale. Ma è qualcosa di simile al tabù nei linguaggi funzionali. Quali sono le ragioni?

La mia domanda è specifica per lo stile di programmazione funzionale. Non tutti i linguaggi / paradigmi di programmazione.


6
Un programma senza effetti collaterali è inutile, quindi gli effetti collaterali non sono né malvagi né tabù. Ma FP incoraggia la delimitazione del codice con effetti collaterali, quindi una parte del codice più ampia possibile sono funzioni libere da effetti collaterali. Questo è incoraggiato perché le funzioni e i sottosistemi liberi da effetti collaterali sono più facili da capire, più facili da analizzare, più facili da testare e più facili da ottimizzare.
JacquesB,

@JacquesB Sarebbe una buona risposta per spiegare perché sono più facili da capire, più facili da analizzare, più facili da testare e più facili da ottimizzare.
ceving il

Risposte:


72

Scrivere le tue funzioni / metodi senza effetti collaterali - quindi sono pure funzioni - rende più facile ragionare sulla correttezza del tuo programma.

Inoltre semplifica la composizione di tali funzioni per creare nuovi comportamenti.

Rende anche possibili alcune ottimizzazioni, in cui il compilatore può ad esempio memorizzare i risultati delle funzioni o utilizzare Common Subexpression Elimination.

Modifica: su richiesta di Benjol: poiché gran parte del tuo stato è archiviato nello stack (flusso di dati, non flusso di controllo, come Jonas lo ha chiamato qui ), puoi parallelizzare o riordinare altrimenti l'esecuzione di quelle parti del tuo calcolo che sono indipendenti da l'un l'altro. Puoi facilmente trovare quelle parti indipendenti perché una parte non fornisce input all'altra.

In ambienti con debugger che ti consentono di ripristinare lo stack e riprendere il calcolo (come Smalltalk), avere funzioni pure significa che puoi facilmente vedere come cambia un valore, perché gli stati precedenti sono disponibili per l'ispezione. In un calcolo ricco di mutazione, a meno che non si aggiungano esplicitamente azioni do / annulla alla struttura o all'algoritmo, non è possibile visualizzare la cronologia del calcolo. (Ciò si ricollega al primo paragrafo: la scrittura di funzioni pure semplifica il controllo della correttezza del programma.)


4
Forse potresti aggiungere qualcosa sulla concorrenza nella tua risposta?
Benjol,

5
Le funzioni senza effetti collaterali sono più facili da testare e riutilizzare.
LennyProgrammers,

@ Lenny222: il riutilizzo era ciò a cui accennavo parlando della composizione delle funzioni.
Frank Shearar,

@Frank: Ah, ok, navigazione troppo superficiale. :)
LennyProgrammers,

@ Lenny222: va bene; è probabilmente una buona cosa spiegarlo.
Frank Shearar,

23

Da un articolo sulla programmazione funzionale :

In pratica, le applicazioni devono avere alcuni effetti collaterali. Simon Peyton-Jones, un importante collaboratore del linguaggio di programmazione funzionale Haskell, ha dichiarato quanto segue: "Alla fine, qualsiasi programma deve manipolare lo stato. Un programma che non ha effetti collaterali è una specie di scatola nera. Tutto quello che puoi dire è che la scatola diventa più calda. " ( http://oscon.blip.tv/file/324976 ) La chiave è limitare gli effetti collaterali, identificarli chiaramente ed evitare di disperderli nel codice.



23

Hai sbagliato, la programmazione funzionale promuove la limitazione degli effetti collaterali per rendere i programmi facili da capire e ottimizzare. Anche Haskell ti permette di scrivere su file.

In sostanza quello che sto dicendo è che i programmatori funzionali non pensano che gli effetti collaterali siano cattivi, pensano semplicemente che limitare l'uso degli effetti collaterali sia buono. So che può sembrare una distinzione così semplice ma fa la differenza.


Ecco perché sono "qualcosa di simile al tabù": gli FPL ti incoraggiano a limitare gli effetti collaterali.
Frank Shearar,

+1 per l'approccio. gli effetti collaterali esistono ancora. anzi, sono limitati
Belun,

Per chiarimenti, non ho detto "perché gli effetti collaterali non sono consentiti nella programmazione funzionale" o "perché gli effetti collaterali non sono necessari". So che è consentito nei linguaggi funzionali e talvolta è d'obbligo. Ma è molto scoraggiato nella programmazione funzionale. Perché? Questa era la mia domanda.
Gulshan,

@Gulshan - Perché gli effetti collaterali rendono i programmi più difficili da comprendere e ottimizzare.
ChaosPandion,

nel caso di haskell, il punto principale non è "limitare gli effetti collaterali". gli effetti collaterali sono impossibili da esprimere nella LINGUA. ciò che funzioni come readFilestanno sta definendo una sequenza di azioni. questa sequenza è funzionalmente pura ed è un po 'come un albero astratto che descrive COSA fare. gli effetti collaterali sporchi effettivi vengono quindi eseguiti dal runtime.
Sara

13

Alcune note:

  • Le funzioni senza effetti collaterali possono essere eseguite in modo banale in parallelo, mentre le funzioni con effetti collaterali richiedono in genere una sorta di sincronizzazione.

  • Le funzioni senza effetti collaterali consentono un'ottimizzazione più aggressiva (ad esempio utilizzando in modo trasparente una cache dei risultati), poiché finché otteniamo il risultato giusto, non importa nemmeno se la funzione è stata effettivamente eseguita


Punto molto interessante: non importa nemmeno se la funzione è stata davvero eseguita . Sarebbe interessante finire con un compilatore in grado di sbarazzarsi delle chiamate successive a funzioni gratuite senza effetti collaterali dati parametri equivalenti.
Noel Widmer,

1
@NoelWidmer Qualcosa del genere esiste già. Oracle PL / SQL offre una deterministicclausola per le funzioni senza effetti collaterali, quindi non vengono eseguite più spesso del necessario.
user281377,

Wow! Tuttavia, penso che le lingue debbano essere semanticamente espressive in modo che il compilatore possa capirlo da solo senza dover specificare un flag esplicito (non sono sicuro di cosa sia una clausola). Una soluzione potrebbe essere quella di specificare i parametri da rendere mutabili / immutabili, in generale, ciò richiederebbe un sistema di tipo forte in cui il compilatore può fare ipotesi sugli effetti collaterali. E la funzione dovrebbe essere in grado di essere disattivata se lo si desidera. Disattivazione anziché attivazione. Questa è solo la mia opinione, basata sulla limitata conoscenza che ho da quando ho letto la tua risposta :)
Noel Widmer,

La deterministicclausola è solo una parola chiave che dice al compilatore che questa è una funzione deterministica, paragonabile a come la finalparola chiave in Java dice al compilatore che la variabile non può cambiare.
user281377,

11

Lavoro principalmente nel codice funzionale ora e da quella prospettiva sembra accecantemente ovvio. Gli effetti collaterali creano un enorme onere mentale per i programmatori che cercano di leggere e comprendere il codice. Non noti questo onere finché non ti liberi da un po ', quindi improvvisamente devi leggere di nuovo il codice con effetti collaterali.

Considera questo semplice esempio:

val foo = 42
// Several lines of code you don't really care about, but that contain a
// lot of function calls that use foo and may or may not change its value
// by side effect.

// Code you are troubleshooting
// What's the expected value of foo here?

In un linguaggio funzionale, so che fooè ancora 42. Non devo nemmeno guardare il codice in mezzo, tanto meno capirlo, o guardare le implementazioni delle funzioni che chiama.

Tutto ciò che riguarda la concorrenza, la parallelizzazione e l'ottimizzazione è bello, ma è quello che gli scienziati informatici hanno messo sulla brochure. Non doversi chiedermi chi sta mutando la tua variabile e quando è ciò che mi piace davvero nella pratica quotidiana.


6

Poche o nessuna lingua rende impossibile causare effetti collaterali. Le lingue completamente prive di effetti collaterali sarebbero proibitivamente difficili (quasi impossibili) da usare, se non con una capacità molto limitata.

Perché gli effetti collaterali sono considerati malvagi?

Perché rendono molto più difficile ragionare esattamente su ciò che fa un programma e dimostrare che fa ciò che ti aspetti che faccia.

A un livello molto alto, immagina di testare un intero sito Web a 3 livelli con solo test black-box. Certo, è fattibile, a seconda della scala. Ma ci sono sicuramente molte duplicazioni in corso. E se c'è è un bug (che è legato ad un effetto collaterale), allora si potrebbe potenzialmente rompere l'intero sistema per ulteriori test, fino a quando il bug viene diagnosticata e fissato, e la correzione viene distribuito per l'ambiente di test.

Benefici

Ora ridimensionalo. Se fossi abbastanza bravo a scrivere codice gratuito con effetti collaterali, quanto saresti più veloce a ragionare su ciò che ha fatto un codice esistente? Quanto più velocemente potresti scrivere unit test? Come vi sentireste sicuri che il codice senza effetti collaterali è stato garantito privo di bug, e che gli utenti potrebbero limitare la loro esposizione ad eventuali bug che ha avuto?

Se il codice non ha effetti collaterali, il compilatore potrebbe anche avere ulteriori ottimizzazioni che potrebbe eseguire. Potrebbe essere molto più semplice implementare tali ottimizzazioni. Potrebbe essere molto più semplice anche concettualizzare un'ottimizzazione per il codice libero degli effetti collaterali, il che significa che il fornitore del compilatore potrebbe implementare ottimizzazioni che sono difficili da impossibili a impossibili nel codice con effetti collaterali.

La concorrenza è inoltre drasticamente più semplice da implementare, generare automaticamente e ottimizzare quando il codice non ha effetti collaterali. Questo perché tutti i pezzi possono essere valutati in modo sicuro in qualsiasi ordine. Consentire ai programmatori di scrivere codice altamente concorrenziale è ampiamente considerata la prossima grande sfida che l'Informatica deve affrontare e una delle poche siepi rimaste contro la Legge di Moore .


1
Ada rende molto difficile causare effetti collaterali. Non è impossibile però, ma sai chiaramente cosa fai allora.
mouviciel,

@mouviciel: Penso che ci siano almeno alcune lingue utili là fuori che rendono molto difficili gli effetti collaterali e provo a relegarli in Monads.
Merlyn Morgan-Graham,

4

Gli effetti collaterali sono come "perdite" nel tuo codice che dovranno essere gestite in seguito, da te o da un collega ignaro.

I linguaggi funzionali evitano variabili di stato e dati mutabili come modo per rendere il codice meno dipendente dal contesto e più modulare. La modularità assicura che il lavoro di uno sviluppatore non influenzerà / minerà il lavoro di un altro.

Il ridimensionamento del tasso di sviluppo in base alle dimensioni del team è oggi un "Santo Graal" di sviluppo software. Quando si lavora con altri programmatori, poche cose sono importanti quanto la modularità. Anche il più semplice degli effetti collaterali logici rende la collaborazione estremamente difficile.


+1 - "o qualche collega ignaro"
Merlyn Morgan-Graham,

1
-1 per gli effetti collaterali che sono "perdite che devono essere gestite". La creazione di "effetti collaterali" (codice non puro funzionale) è l'intero scopo di scrivere qualsiasi programma per computer non banale.
Mason Wheeler,

Questo commento arriva sei anni dopo, ma ci sono effetti collaterali e poi ci sono effetti collaterali. Il tipo desiderabile di effetti collaterali, facendo I / O e così via, sono effettivamente necessari per qualsiasi programma, perché in qualche modo devi dare i tuoi risultati all'utente - ma l'altro tipo di effetti collaterali, in cui il tuo codice cambia stato senza un buon ragione come fare I / O, sono davvero una "perdita" che dovrà essere gestita in seguito. L'idea di base è la separazione comando-query : una funzione che restituisce un valore non dovrebbe avere effetti collaterali.
rmunn,

4

Bene, IMHO, questo è abbastanza ipocrita. A nessuno piacciono gli effetti collaterali, ma tutti ne hanno bisogno.

Ciò che è così pericoloso riguardo agli effetti collaterali è che se si chiama una funzione, ciò potrebbe avere un effetto non solo sul modo in cui la funzione si comporta quando viene chiamata la prossima volta, ma probabilmente ha questo effetto su altre funzioni. Pertanto, gli effetti collaterali introducono comportamenti imprevedibili e dipendenze non banali.

I paradigmi di programmazione come OO e funzionale affrontano entrambi questo problema. OO riduce il problema imponendo una separazione delle preoccupazioni. Ciò significa che lo stato dell'applicazione, che consiste in molti dati mutabili, è incapsulato in oggetti, ognuno dei quali è responsabile solo del mantenimento del proprio stato. In questo modo il rischio di dipendenze è ridotto e i problemi sono molto più isolati e più facili da rintracciare.

La programmazione funzionale ha un approccio molto più radicale, in cui lo stato dell'applicazione è semplicemente immutabile dal punto di vista del programmatore. Questa è una bella idea, ma rende la lingua inutile da sola. Perché? Perché QUALSIASI operazione di I / O ha effetti collaterali. Non appena si legge da qualsiasi flusso di input, è probabile che lo stato dell'applicazione cambi, poiché la volta successiva che si richiama la stessa funzione, è probabile che il risultato sia diverso. È possibile che tu stia leggendo dati diversi o - anche una possibilità - l'operazione potrebbe non riuscire. Lo stesso vale per l'output. Anche l'output è un'operazione con effetti collaterali. Al giorno d'oggi questo non è ciò che realizzi spesso, ma immagina di avere solo 20 KB per l'output e se l'output è maggiore, la tua app si arresta in modo anomalo perché sei a corto di spazio su disco o altro.

Quindi sì, gli effetti collaterali sono cattivi e pericolosi dal punto di vista di un programmatore. La maggior parte dei bug deriva dal modo in cui alcune parti dello stato dell'applicazione sono interbloccate in modo quasi oscuro, attraverso effetti collaterali non considerati e spesso inutili. Dal punto di vista di un utente, gli effetti collaterali sono il punto di usare un computer. A loro non importa cosa succede dentro o come è organizzato. Fanno qualcosa e si aspettano che il computer cambi di conseguenza.


interessante la programmazione logica non solo non ha effetti collaterali funzionali; ma non puoi nemmeno cambiare il valore di una variabile una volta assegnato.
Ilan,

@Ilan: questo vale anche per alcuni linguaggi funzionali ed è uno stile facile da adottare.
back2dos,

"La programmazione funzionale ha un approccio molto più radicale, in cui lo stato dell'applicazione è semplicemente immutabile dal punto di vista del programmatore. Questa è una buona idea, ma rende il linguaggio inutile da solo. Perché? Perché QUALSIASI operazione I / O ha un lato effetti ": FP non proibisce gli effetti collaterali, ma li limita quando non è necessario. Ad esempio (1) I / O -> sono necessari effetti collaterali; (2) calcolo di una funzione aggregata da una sequenza di valori -> effetto collaterale (ad es. Per loop con accumulatore variabile) non necessario.
Giorgio,

2

Qualsiasi effetto collaterale introduce parametri di input / output extra che devono essere presi in considerazione durante il test.

Ciò rende la convalida del codice molto più complessa in quanto l'ambiente non può essere limitato al solo codice in fase di convalida, ma deve portare in tutto o in parte l'ambiente circostante (il globale che viene aggiornato vive in quel codice laggiù, che a sua volta dipende da quello codice, che a sua volta dipende dalla vita all'interno di un server Java EE completo ....)

Cercando di evitare effetti collaterali si limita la quantità di esternalismo necessaria per eseguire il codice.


1

Nella mia esperienza, un buon design nella programmazione orientata agli oggetti impone l'uso di funzioni che hanno effetti collaterali.

Ad esempio, prendi un'applicazione desktop UI di base. Potrei avere un programma in esecuzione che ha sul suo heap un oggetto grafico che rappresenta lo stato corrente del modello di dominio del mio programma. I messaggi arrivano agli oggetti in quel grafico (ad esempio, tramite le chiamate di metodi invocate dal controller del livello dell'interfaccia utente). Il grafico a oggetti (modello di dominio) sull'heap viene modificato in risposta ai messaggi. Gli osservatori del modello vengono informati di eventuali cambiamenti, l'interfaccia utente e forse altre risorse vengono modificate.

Lungi dall'essere malvagi, la corretta disposizione di questi effetti collaterali che modificano l'heap e che modificano lo schermo sono al centro del design di OO (in questo caso il modello MVC).

Naturalmente, ciò non significa che i tuoi metodi dovrebbero avere effetti collaterali arbitrari. E le funzioni senza effetti collaterali hanno un ruolo nel migliorare la leggibilità e talvolta le prestazioni del tuo codice.


1
Gli osservatori (compresa l'interfaccia utente) dovrebbero scoprire le modifiche iscrivendosi ai messaggi / eventi inviati dall'oggetto. Questo non è un effetto collaterale a meno che l'oggetto non modifichi direttamente l'osservatore, il che sarebbe un cattivo design.
ChrisF

1
@ChrisF Sicuramente è un effetto collaterale. Il messaggio passato all'osservatore (in una lingua OO molto probabilmente una chiamata di metodo su un'interfaccia) porterà alla modifica dello stato del componente UI sull'heap (e questi oggetti heap sono visibili ad altre parti del programma). Il componente UI non è né un parametro del metodo né il valore restituito. In senso formale, affinché una funzione sia libera da effetti collaterali deve essere idempotente. La notifica nel modello MVC non è, ad esempio l'interfaccia utente può visualizzare un elenco di messaggi che ha ricevuto - console - la chiamata due volte comporta un diverso stato del programma.
flamingpenguin,

0

Il male è un po 'esagerato .. tutto dipende dal contesto dell'uso della lingua.

Un'altra considerazione a quelle già menzionate è che rende le prove della correttezza di un programma molto più semplici se non ci sono effetti collaterali funzionali.


0

Come indicato in precedenza, i linguaggi funzionali non impediscono così tanto al codice di avere effetti collaterali, in quanto ci forniscono strumenti per gestire quali effetti collaterali possono verificarsi in un determinato codice e quando.

Questo risulta avere conseguenze molto interessanti. Innanzitutto, e ovviamente, ci sono numerose cose che puoi fare con il codice libero ad effetto collaterale, che sono già state descritte. Ma ci sono altre cose che possiamo fare anche quando lavoriamo con il codice che ha effetti collaterali:

  • Nel codice con stato modificabile, possiamo gestire l'ambito dello stato in modo da garantire staticamente che non possa fuoriuscire al di fuori di una determinata funzione, questo ci consente di raccogliere immondizia senza contare i riferimenti o schemi di stile mark-and-sweep , ma assicurati comunque che non rimangano riferimenti. Le stesse garanzie sono utili anche per mantenere informazioni sensibili sulla privacy, ecc. (Questo può essere ottenuto usando la monade ST in haskell)
  • Quando si modifica lo stato condiviso in più thread, è possibile evitare la necessità di blocchi monitorando le modifiche ed eseguendo un aggiornamento atomico al termine di una transazione, oppure eseguendo il rollback della transazione e ripetendola se un altro thread ha apportato una modifica in conflitto. Ciò è possibile solo perché possiamo garantire che il codice non abbia effetti diversi dalle modifiche dello stato (che possiamo abbandonare felicemente). Questo viene eseguito dalla monade STM (Software Transactional Memory) di Haskell.
  • possiamo tracciare gli effetti del codice e insignificarlo banalmente, filtrando tutti gli effetti che potrebbe essere necessario per essere sicuri, in modo da consentire (ad esempio) l'esecuzione del codice immesso dall'utente su un sito Web in modo sicuro

0

In basi di codice complesse, le interazioni complesse di effetti collaterali sono la cosa più difficile che trovo a ragionare. Posso solo parlare personalmente dato il modo in cui funziona il mio cervello. Effetti collaterali e stati persistenti e input mutanti e così via mi fanno pensare a "quando" e "dove" le cose accadono per ragionare sulla correttezza, non solo "cosa" sta accadendo in ogni singola funzione.

Non posso semplicemente concentrarmi su "cosa". Non posso concludere dopo aver testato a fondo una funzione che provoca effetti collaterali che diffonderà un'aria di affidabilità in tutto il codice che lo utilizza, poiché i chiamanti potrebbero ancora utilizzarlo in modo errato chiamandolo nel momento sbagliato, dal thread sbagliato, nel modo sbagliato ordine. Nel frattempo una funzione che non causa effetti collaterali e restituisce semplicemente un nuovo output dato un input (senza toccarlo) è praticamente impossibile da usare in questo modo.

Ma sono un tipo pragmatico, penso, o almeno provo a esserlo, e non penso che dobbiamo necessariamente eliminare tutti gli effetti collaterali al minimo indispensabile per ragionare sulla correttezza del nostro codice (almeno Lo troverei molto difficile da fare in lingue come C). Dove trovo molto difficile ragionare sulla correttezza è quando abbiamo la combinazione di complessi flussi di controllo ed effetti collaterali.

Flussi di controllo complessi per me sono quelli che sono di natura grafica, spesso ricorsivi o ricorsivi (code di eventi, ad esempio, che non chiamano direttamente gli eventi in modo ricorsivo ma sono "di tipo ricorsivo" in natura), forse fanno cose nel processo di attraversamento di un'effettiva struttura di un grafico collegato o nell'elaborazione di una coda di eventi non omogenea che contiene una miscela eclettica di eventi da elaborare che ci porta a tutti i tipi di diverse parti della base di codice e tutti a innescare diversi effetti collaterali. Se provassi a disegnare tutti i posti che alla fine finirai nel codice, assomiglierebbe a un grafico complesso e potenzialmente con nodi nel grafico che non ti saresti mai aspettato sarebbero stati lì in quel dato momento, e dato che sono tutti causando effetti collaterali,

I linguaggi funzionali possono avere flussi di controllo estremamente complessi e ricorsivi, ma il risultato è così facile da comprendere in termini di correttezza perché non ci sono tutti i tipi di effetti collaterali eclettici che si verificano nel processo. È solo quando complessi flussi di controllo incontrano effetti collaterali eclettici che trovo che induca il mal di testa a cercare di comprendere l'insieme di ciò che sta accadendo e se farà sempre la cosa giusta.

Quindi, quando ho questi casi, trovo spesso molto difficile, se non impossibile, sentirmi molto fiducioso sulla correttezza di tale codice, figuriamoci molto fiducioso di poter apportare modifiche a tale codice senza inciampare in qualcosa di inaspettato. Quindi la soluzione per me è quella di semplificare il flusso di controllo o minimizzare / unificare gli effetti collaterali (unificando, intendo come causare un solo tipo di effetto collaterale a molte cose durante una particolare fase del sistema, non due o tre o un dozzina). Ho bisogno che accada una di queste due cose per consentire al mio cervello semplice di sentirsi sicuro della correttezza del codice esistente e della correttezza dei cambiamenti che presento. È abbastanza facile essere sicuri della correttezza del codice che introduce effetti collaterali se gli effetti collaterali sono uniformi e semplici insieme al flusso di controllo, in questo modo:

for each pixel in an image:
    make it red

È abbastanza facile ragionare sulla correttezza di tale codice, ma principalmente perché gli effetti collaterali sono così uniformi e il flusso di controllo è così semplice. Ma diciamo che avevamo un codice come questo:

for each vertex to remove in a mesh:
     start removing vertex from connected edges():
         start removing connected edges from connected faces():
             rebuild connected faces excluding edges to remove():
                  if face has less than 3 edges:
                       remove face
             remove edge
         remove vertex

Quindi questo è pseudocodice ridicolmente semplificato che in genere implicherebbe molte più funzioni e cicli annidati e molte altre cose che dovrebbero andare avanti (aggiornamento di più mappe di trama, pesi ossei, stati di selezione, ecc.), Ma anche lo pseudocodice rende così difficile ragione della correttezza a causa dell'interazione del complesso flusso di controllo simile a un grafico e degli effetti collaterali in corso. Quindi una strategia per semplificare è quella di rinviare l'elaborazione e concentrarsi solo su un tipo di effetto collaterale alla volta:

for each vertex to remove:
     mark connected edges
for each marked edge:
     mark connected faces
for each marked face:
     remove marked edges from face
     if num_edges < 3:
          remove face

for each marked edge:
     remove edge
for each vertex to remove:
     remove vertex

... qualcosa in tal senso come una ripetizione di semplificazione. Ciò significa che stiamo attraversando i dati più volte, il che comporta sicuramente un costo computazionale, ma spesso troviamo che possiamo multithreading di tale codice risultante più facilmente, ora che gli effetti collaterali e i flussi di controllo hanno assunto questa natura uniforme e più semplice. Inoltre, ogni loop può essere reso più compatibile con la cache rispetto al attraversamento del grafico collegato e causando effetti collaterali mentre procediamo (es: utilizzare un set di bit parallelo per contrassegnare ciò che deve essere attraversato in modo che possiamo quindi fare i passaggi differiti in ordine sequenziale ordinato utilizzando maschere di bit e FFS). Ma soprattutto, trovo che la seconda versione sia molto più facile da ragionare in termini di correttezza e di cambiamento senza causare bug. Così che'

Dopotutto, abbiamo bisogno che si verifichino effetti collaterali ad un certo punto, altrimenti avremmo solo funzioni che trasmettono dati senza un posto dove andare. Spesso dobbiamo registrare qualcosa su un file, visualizzare qualcosa su uno schermo, inviare i dati attraverso un socket, qualcosa di questo tipo e tutte queste cose sono effetti collaterali. Ma possiamo sicuramente ridurre il numero di effetti collaterali superflui che si verificano e anche ridurre il numero di effetti collaterali che si verificano quando i flussi di controllo sono molto complicati, e penso che sarebbe molto più facile evitare i bug se lo facessimo.


-1

Non è male. A mio avviso, è necessario distinguere i due tipi di funzione - con effetti collaterali e senza. La funzione senza effetti collaterali: - restituisce sempre la stessa cosa con gli stessi argomenti, quindi ad esempio tale funzione senza argomenti non ha senso. - Ciò significa anche che l'ordine in cui alcune di queste funzioni sono chiamate non ha alcun ruolo - deve essere in grado di funzionare e può essere eseguito il debug da solo (!), Senza un altro codice. E ora, lol, guarda cosa fa JUnit. Una funzione con effetti collaterali: - ha una sorta di "perdite", ciò che può essere evidenziato automaticamente - è molto importante il debug e la ricerca di errori, che generalmente sono causati da effetti collaterali. - Qualsiasi funzione con effetti collaterali ha anche una "parte" di se stessa senza effetti collaterali, che può anche essere separata automaticamente. Così malvagi sono quegli effetti collaterali,


questo non sembra offrire nulla di sostanziale rispetto ai punti formulati e spiegati nelle precedenti 12 risposte
moscerino del
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.