私の理解では、do モナドの場合、各ステップには継続と終了があります。
純粋性、強力な型、およびモナドが次のことができることを確認しました。
...
- 実行のさまざまなフェーズ間の混乱から生じる可能性のあるバグを防ぎます。
私の質問は:モナドが防ぐバグのカテゴリは何ですか?
私の理解では、do モナドの場合、各ステップには継続と終了があります。
純粋性、強力な型、およびモナドが次のことができることを確認しました。
...
- 実行のさまざまなフェーズ間の混乱から生じる可能性のあるバグを防ぎます。
私の質問は:モナドが防ぐバグのカテゴリは何ですか?
通常の型がデータを区別する方法を提供するように、モナドは結果を区別する方法を提供します。
Elixir
これは、Erlang 上のほぼ純粋な関数型言語であるの例です。この例は、私の仕事で頻繁に発生する実際の状況から派生したものです。
def handle_call(:get_config_foo, _, state) do:
{:reply, state.foo, state}
end
def handle_call(:get_bar, _, state) do:
{:reply, state.bar, state}
end
def handle_call({:set_bar, bar}, _, state) do:
{:reply, :ok, %{state | bar: bar}}
end
これはGenServerの API を定義します。これは、いくつかを保持state
し、クエリや変更を可能にする小さな Erlang ノードです。最初の呼び出しは、不変の構成設定:get_config_foo
を読み取ります。呼び出しの 2 番目のセットおよびは、変更可能な状態変数を取得および設定します。:get_bar
{:set_bar, bar}
次のバグを防ぐために、ここにモナドがあればいいのにと思います。
def handle_call({:set_bar, bar}, _, state) do:
{:reply, :ok, %{state | foo: bar}}
end
あなたは間違いを見つけることができますか?さて、readonly 値を書きました。Elixir にはこれを妨げるものは何もありません。GenServer 状態の一部を読み取り専用としてマークし、他の部分を読み取り/書き込みとしてマークすることはできません。
Haskell では、さまざまな種類の効果を指定するためにさまざまなモナドを使用できます。読み取り専用状態 ( Reader
) と読み取り/書き込み状態は次のとおりです。
data Reader r a = Reader (r -> a)
data State s a = State (s -> (a, s))
Reader
設定状態にアクセスしてr
何らかの値を返すことができますa
。State
状態を読み取り、何らかの値を返し、状態を変更することができます。どちらもモナドであり、基本的には、これらの状態アクセスを命令型の方法で順番に連鎖できることを意味します。ではReader
、最初に 1 つの構成設定を読み取り、次に (その最初の設定に基づいて) 別の設定を読み取ることができます。ではState
、状態を読み取り、(読み取った内容に基づいて) さらに変更することができます。ただし、実行中に状態を変更することはできません。Reader
これを繰り返させてください。いくつかの呼び出しをバインドすると、その間にリーダーの状態を変更Reader
できないことが保証されます。getConfigFoo1 :: Reader Config Foo1
と がありgetConfigFoo2 :: Foo1 -> Reader Config Foo2
、 がある場合、両方のクエリが同じ で実行されるgetAllConfig = getConfigFoo1 >>= getConfigFoo2
ことが確実Config
です。Elixir にはこの機能がなく、上記のバグが見過ごされてしまいます。
これが役立つその他の効果は、(Writer
ロギングなどの書き込み専用状態) とEither
(例外処理) です。またはWriter
の代わりにある場合、状態が常に追加されるだけであることを確認できます。があれば、発生する可能性のある例外の種類を正確に把握できます。これは、ロギングと例外処理に使用するよりもはるかに優れています。Reader
State
Either
IO