さらに別のFP +副作用の質問で申し訳ありませんが、私にこれに完全に答える既存の質問を見つけることができませんでした。
関数型プログラミングの私の(限られた)理解は、状態/副作用を最小限に抑え、ステートレスロジックから分離する必要があるということです。
また、これに対するHaskellのアプローチであるIOモナドを収集します。IOモナドは、プログラム自体のスコープ外であると見なされる、後で実行するために、ステートフルアクションをコンテナにラップすることによってこれを実現します。
私はこのパターンを理解しようとしていますが、実際にはPythonプロジェクトで使用するかどうかを決定するため、Haskell固有の仕様を避ける必要があります。
原油の着信。
私のプログラムがXMLファイルをJSONファイルに変換する場合:
def main():
xml_data = read_file('input.xml') # impure
json_data = convert(xml_data) # pure
write_file('output.json', json_data) # impure
これを行うためのIOモナドのアプローチは効果的ではありません:
steps = list(
read_file,
convert,
write_file,
)
その後、実際にそれらのステップを呼び出すのではなく、インタープリターにそれを行わせることで、責任を放棄しますか?
または別の言い方をすれば、それは次のように書くことです:
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
それから他の誰かが電話することを期待しinner()
、あなたの仕事main()
は純粋だから終わったと言います。
プログラム全体は、基本的にIOモナドに含まれることになります。
コードが実際に実行されると、ファイルを読み込んだ後のすべてがそのファイルの状態に依存するため、命令型実装と同じ状態関連のバグに苦しむことになります。
私はステートフルな振る舞いを減らして分離することの利点を完全に感謝しています。それが実際に命令型バージョンをそのように構成した理由です。convert()
完全に純粋であり、キャッシュ可能性、スレッドセーフなどの利点を享受できることを願っています。
また、モナド型は、特に同等の型で動作するパイプラインで役立つことがありますが、既にそのようなパイプラインにない限り、IOがモナドを使用する理由がわかりません。
IOモナドパターンがもたらす副作用に対処するための追加の利点はありますか?
main
HaskellプログラムのタイプはIO ()
IOアクションであることに注意してください。これは実際には関数ではありません。それはだ値。プログラム全体は、言語ランタイムに何をすべきかを指示する命令を含む純粋な値です。すべての不純なもの(実際にIOアクションを実行する)は、プログラムの範囲外です。
read_file
)を取得し、それを次の計算の引数()として使用する場合write_file
です。一連の独立したアクションだけがあれば、Monadは必要ありません。