Ci scusiamo per l'ennesima domanda sugli effetti collaterali FP +, ma non sono riuscito a trovarne uno esistente che mi ha risposto abbastanza bene.
La mia comprensione (limitata) della programmazione funzionale è che gli effetti di stato / lato dovrebbero essere minimizzati e tenuti separati dalla logica stateless.
Ho anche capito che l'approccio di Haskell a questo, la monade IO, lo raggiunge avvolgendo azioni di stato in un contenitore, per un'esecuzione successiva, considerata al di fuori dell'ambito del programma stesso.
Sto cercando di capire questo schema, ma in realtà per determinare se usarlo in un progetto Python, quindi voglio evitare le specifiche Haskell se possibile.
Esempio grezzo in arrivo.
Se il mio programma converte un file XML in un file JSON:
def main():
xml_data = read_file('input.xml') # impure
json_data = convert(xml_data) # pure
write_file('output.json', json_data) # impure
L'approccio del monade IO non è efficace in questo modo:
steps = list(
read_file,
convert,
write_file,
)
quindi assolvere la responsabilità non effettivamente chiamando quei passaggi, ma lasciando che sia l'interprete a farlo?
In altre parole, è come scrivere:
def main(): # pure
def inner(): # impure
xml_data = read_file('input.xml')
json_data = convert(xml_data)
write_file('output.json', json_data)
return inner
quindi aspettati che qualcun altro chiami inner()
e dichiari che il tuo lavoro è finito perché main()
è puro.
L'intero programma finirà per essere contenuto nella monade IO, in pratica.
Quando il codice è effettivamente eseguito , tutto ciò che segue la lettura del file dipende dallo stato di quel file, quindi continuerà a soffrire degli stessi bug legati allo stato dell'implementazione imperativa, quindi hai effettivamente guadagnato qualcosa, come programmatore che manterrà questo?
Apprezzo pienamente il vantaggio di ridurre e isolare il comportamento di stato, che è in effetti il motivo per cui ho strutturato la versione imperativa del genere: raccogliere input, fare roba pura, sputare uscite Speriamo che convert()
possa essere completamente puro e sfruttare i vantaggi di cachability, threadsafety, ecc.
Apprezzo anche che i tipi monadici possano essere utili, specialmente nelle pipeline che operano su tipi comparabili, ma non vedo perché IO debba usare le monadi se non già in una tale pipeline.
C'è qualche ulteriore vantaggio nell'affrontare gli effetti collaterali che porta il pattern di monade IO, che mi manca?