Désolé pour encore une autre question d'effets secondaires FP +, mais je n'ai pas pu trouver une question existante qui répondait tout à fait à moi.
Ma compréhension (limitée) de la programmation fonctionnelle est que les effets d'état / secondaires doivent être minimisés et séparés de la logique sans état.
Je rassemble également l'approche de Haskell à ce sujet, la monade IO, atteint cet objectif en enveloppant les actions avec état dans un conteneur, pour une exécution ultérieure, considérée en dehors de la portée du programme lui-même.
J'essaie de comprendre ce modèle, mais en fait de déterminer s'il faut l'utiliser dans un projet Python, donc je veux éviter les spécificités de Haskell si possible.
Exemple brut entrant.
Si mon programme convertit un fichier XML en fichier JSON:
def main():
xml_data = read_file('input.xml') # impure
json_data = convert(xml_data) # pure
write_file('output.json', json_data) # impure
L'approche de la monade IO n'est-elle pas efficace pour ce faire:
steps = list(
read_file,
convert,
write_file,
)
alors se dégager de sa responsabilité en n'appelant pas réellement ces étapes, mais en laissant l'interprète le faire?
Autrement dit, c'est comme écrire:
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
puis attendre que quelqu'un d'autre appelle inner()
et dire que votre travail est fait parce que main()
c'est pur.
Tout le programme va finir par être contenu dans la monade IO, essentiellement.
Lorsque le code est réellement exécuté , tout après la lecture du fichier dépend de l'état de ce fichier, il souffrira donc toujours des mêmes bogues liés à l'état que l'implémentation impérative, alors avez-vous réellement gagné quelque chose, en tant que programmeur qui le maintiendra?
J'apprécie totalement l'avantage de réduire et d' isoler les comportements avec état, c'est pourquoi j'ai structuré la version impérative comme ça: rassembler des entrées, faire des trucs purs, cracher des sorties. Espérons que cela convert()
peut être complètement pur et profiter des avantages de la cachabilité, de la sécurité des fils, etc.
J'apprécie également que les types monadiques puissent être utiles, en particulier dans les pipelines fonctionnant sur des types comparables, mais je ne vois pas pourquoi les entrées-sorties devraient utiliser des monades à moins qu'elles ne soient déjà dans un tel pipeline.
Y a-t-il un avantage supplémentaire à gérer les effets secondaires que le modèle de monade IO apporte, ce qui me manque?
main
un programme Haskell est IO ()
- une action d'E / S. Ce n'est pas du tout une fonction; c'est une valeur . L'ensemble de votre programme est une valeur pure contenant des instructions qui indiquent au runtime de langue ce qu'il doit faire. Tous les trucs impurs (en fait les actions d'E / S) sortent du cadre de votre programme.
read_file
) et à l'utiliser comme argument pour le suivant ( write_file
). Si vous n'aviez qu'une séquence d'actions indépendantes, vous n'auriez pas besoin d'une Monade.