Es tut mir leid für eine weitere Frage zu FP + -Nebenwirkungen, aber ich konnte keine existierende finden, die dies für mich ganz beantwortete.
Mein (begrenztes) Verständnis der funktionalen Programmierung ist, dass Zustände / Nebenwirkungen minimiert und von zustandsloser Logik getrennt werden sollten.
Ich nehme auch Haskells Ansatz dazu zur Kenntnis, die IO-Monade, die dies erreicht, indem sie zustandsbezogene Aktionen zur späteren Ausführung in einen Container packt, der über den Rahmen des Programms hinausgeht.
Ich versuche, dieses Muster zu verstehen, aber tatsächlich zu bestimmen, ob es in einem Python-Projekt verwendet werden soll, also möchte ich Haskell-Besonderheiten vermeiden, wenn möglich.
Rohes Beispiel eingehend.
Wenn mein Programm eine XML-Datei in eine JSON-Datei konvertiert:
def main():
xml_data = read_file('input.xml') # impure
json_data = convert(xml_data) # pure
write_file('output.json', json_data) # impure
Ist der Ansatz der IO-Monade nicht effektiv, um dies zu tun:
steps = list(
read_file,
convert,
write_file,
)
dann entlasten Sie sich von der Verantwortung, indem Sie diese Schritte nicht tatsächlich aufrufen , sondern den Dolmetscher dies tun lassen?
Oder anders ausgedrückt, es ist wie beim Schreiben:
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
Wenn Sie dann erwarten, dass jemand anderes anruft inner()
und sagt, dass Ihre Arbeit erledigt ist, weil sie main()
rein ist.
Das gesamte Programm wird im Grunde genommen in der IO-Monade enthalten sein.
Wenn der Code tatsächlich ausgeführt wird , hängt alles nach dem Lesen der Datei vom Status der Datei ab, sodass immer noch dieselben statusbezogenen Fehler wie bei der Imperativimplementierung auftreten. Haben Sie also als Programmierer, der dies verwaltet, tatsächlich etwas gewonnen?
Ich weiß den Vorteil des Reduzierens und Isolierens von staatlichem Verhalten sehr zu schätzen , weshalb ich die imperative Version so strukturiert habe: Inputs sammeln, reine Sachen machen, Outputs ausspucken. Hoffentlich convert()
kann man völlig rein sein und die Vorteile von Cachefähigkeit, Threadsicherheit usw. nutzen.
Ich weiß auch zu schätzen, dass monadische Typen nützlich sein können, insbesondere in Pipelines, die mit vergleichbaren Typen betrieben werden, aber ich verstehe nicht, warum IO Monaden verwenden sollte, es sei denn, sie befinden sich bereits in einer solchen Pipeline.
Gibt es einen zusätzlichen Vorteil beim Umgang mit Nebenwirkungen, die das E / A-Monadenmuster mit sich bringt, das mir fehlt?
main
in einem Haskell-Programm IO ()
- eine E / A-Aktion ist. Dies ist eigentlich gar keine Funktion; Es ist ein Wert . Ihr gesamtes Programm ist ein reiner Wert, der Anweisungen enthält, die der Laufzeitsprache mitteilen, was sie tun soll. Alle unreinen Dinge (die tatsächlich die E / A-Aktionen ausführen) liegen außerhalb des Bereichs Ihres Programms.
read_file
) als Argument für die nächste verwenden ( write_file
). Wenn Sie nur eine Sequenz unabhängiger Aktionen hätten, bräuchten Sie keine Monade.