さまざまなモナドに関するHaskellの教科書の章を調べていると、著者がbindの詳細とモナドの法則の説明から実際にモナドを使用するまでジャンプすると、何度も迷子になります。突然、「モナドコンテキストで関数を実行する」、「モナドを実行する」などの式がポップアップ表示されます。同様に、ライブラリのドキュメントやモナドトランスフォーマスタックに関する説明では、「モナドのどの選択でも実行できる」関数があるという説明を読んでいます。これは「モナド内で実行される」とはどういう意味ですか?
うまくいきそうにないことが2つあります。
return
、>>=
)と則を持つ型クラスです。したがって、モナド内で何かを「実行」するとは、(a)return
への引数として提供すること、または(b)>>=
を使用してシーケンス化することを意味します。モナドがm a
型の場合、a)の場合somethingはa
関数の型と一致するようにreturn
型でなければなりません。ケースb)の場合somethingは、a -> m b
関数のタイプと一致するように、>>=
タイプの関数である必要があります。これから、>>=
を使用してシーケンスする関数はすべて同じ型シグネチャを持つ必要があり、return
を使用して持ち上げる値は特定のモナドタイプパラメータ。run
、runReader
などのrunState
関数が付属しています。これらの関数はモナドの定義の一部ではなく、単純な関数であり、言語の機能コア以外の特別な命令ステートメントではありません。では、何を「実行」するのでしょうか。これらの概念を明確に理解することは、モナド変換スタックや、Haskellの重要なライブラリや重要なプログラムを理解するために必要と思われる類似の構造を理解するための鍵であると思います。単純に機能的なコードを書くことから、それが何を意味するのかを実際に理解することへの飛躍を支援してくれてありがとう。
>> =を使用してシーケンスする関数は、すべて同じ型シグネチャを持つ必要があります
これはほんの真実です。いくつかのモナドの文脈では、
x >>= f >>= g
どこ
x :: Maybe Int
f :: Int -> Maybe String
g :: String -> Maybe Char
これらはすべて同じモナド(多分)を含む必要がありますが、すべてが同じ型シグネチャを持つわけではないことに注意してください。通常の関数構成と同様に、すべての戻り値の型が同じである必要はありません。1つの関数の入力がその前の関数の出力と一致しているだけです。
これは、疑似コードを使用した「コンテナー内で関数を実行する」の簡単な例です。
「将来のある時点で」文字列を持つコンテナを表すFuture [String]型があるとします。
val Tweet: Future[String] = getTweet()
ここで、文字列にアクセスしたいのですが、コンテキストから文字列(「未来」)を取り出さず、「コンテナ内」の文字列を使用するだけです。
Tweet.map { str =>
println(str)
}
これらの中括弧の中では、あなたは「未来」にいます。例えば:
val Tweet: Future[String] = getTweet()
Tweet.map { str =>
println(str)
}
println("Length of Tweet string is " + Tweet.length) // <== WRONG -- you are not yet in the future
Tweet.lengthがツイートにアクセスしようとしていますコンテナの外。したがって、「コンテナ内にいる」とは、ソースコードを読むときに「マップ(フラットマップなど)の中かっこ内にある」と似ています。コンテナの中に浸しています。
Tweet.map { str =>
println("Length of Tweet string is " + str.length) // <== RIGHT
}
非常に単純な類推ですが、これは一般的にすべてのモナドについて考えるときに便利です。ソースコードでは、「コンテナの内側」はどこにあり、外側はどこにありますか?この場合、長さ関数は将来、または「コンテナー内」で実行されます。