web-dev-qa-db-ja.com

関数間でコンテキスト変数を共有するためのパターン

関数に必要な一連のコンテキスト変数を渡す方法を探しています。

Pythonプログラマーとして、現在、問題を解決する3つの方法を確認できます。それらを明示的な引数、クラスのカプセル化、クロージャー(関数ファクトリ)として渡すことです。

明示的な引数は関数のロジックを不明瞭にする傾向があり、クラスのカプセル化はすべてを実行する何千行ものクラスにつながる傾向があるのに対し、クロージャーはファクトリの作成のためにプログラミングのオーバーヘッドを生じる傾向があることがわかります。

そのような欠点のない機能間で動的に定義されたコンテキスト変数の共有を可能にする他のパターンがあるかどうか疑問に思っていましたか?たとえば、この問題は関数型プログラミングのコンテキストでどのように解決されますか?

5

ReaderモナドまたはStateモナドを調べるかもしれません。それらは、明示的なパラメーターなどに頼ることなく、(純粋、モナド)関数間でデータを共有するために使用できます。

Stateモナドについての 楽しさと利益のためのF# に関するチュートリアルシリーズがあります(F#のワークフローの別名ワークフロー)。これについても説明しました SO answer かなり親しみやすいようです。

他にも Pythonのモナド の実装がいくつかありますが、独自に実装する必要がある場合に参照できます。

多くの人々(私も含む)は最初はモナドに挑戦していることに気づきます。そのため、概念に精通していない場合は、MaybeやEither、そしておそらくReaderやWriterなどの単純なモナドを見てから、Stateに取り組むことをお勧めします。上記にリンクされているPython実装は、オンラインの他の場所(おそらくHaskell)で見つかるであろうものよりも、物事をより明確にするかもしれません)。

いくつかの注意事項:モナドが含まれているため、関数だけのオーバーヘッドがまだあり、これはfunctionsで使用する必要があります;私はあなたがクラスメソッドでこれを行うことができるとは思いません(私は間違っている可能性があります-私はそれを試したことはありません!)。

UPDATE:

上記にリンクした「Pythonのモナド」ページ/ライブラリは実際にはdoes状態モナド実装を持っています。定義と例については、###### StateChanger Monad #########で始まるコードを確認してください。

コメント内の質問に応じて編集:

はい、それがあなたのやり方です-明確にするために、関数を宣言する引数には環境変数を含めるべきではなく、関数が通常必要とするものだけを含める必要があります。モナディックgetおよびset関数を介して環境変数にアクセスできます。

Python上記の "Pythonのモナド"リンクにある表記を使用した例:

@do(StateChanger) # <-- this makes makes it a stateful computation
def my_stateful_function1(arg):
    # do something with `arg` here
    # then put it in the state:
    yield dict_state_set(key, var_from_arg)
    # I believe you can leave out `mreturn` for this

@do(StateChanger)
def my_stateful_function2(arg1, arg2):
    # something with `arg1` here
    # get the state chained via the monad:
    state = yield get_state()
    # do something else stateful:
    yield my_stateful_function1(arg2)
    # do something with `state` dict here
    # return; you have to use `mreturn` instead of `return`:
    mreturn(some_value)

これを実行するには、次のように呼び出します。

ret_val = my_stateful_function2("hello","world").run(initial_state_dict)

そしてあなたの戻り値はタプルになります:

(return_value_of_function, final_state_dict) = ret_val

他のステートフル関数を呼び出すときは、必ずyieldを使用してください。

警告:Python辞書タイプは変更可能であるため、関数の状態の変更には注意してください。状態変数を設定し、それらに(ラムダ)関数を適用します。状態を引き出して無作為に変更するのではなく、これに固執したい場合があります。

4
paul