2015-12-21 6 views
6

ハスケルでは、モナドは関数returnとbindの形で定義されています。戻り値の型はa -> m a、バインドの型はm a -> (a -> m b) -> m bです。その前に指摘されているのはmonads can also be defined in terms of return and joinです。ここで、joinはタイプm (m a) -> m aの関数です。バインドは結合の観点から定義できますが、その逆が可能ですか?結合は結合の観点から定義できますか?モナドでは、バインドの観点から結合できますか?

参加しないと、何とか二重ラップされたモナド値m (m a)を取得した場合、私は何をしたらいいのか分かりません - ファンクタまたはモナド操作のどれも "これが不可能な場合、なぜHaskellと他の多くのモナド実装がバインドの観点からそれらを定義していますか?これは、結合ベースの定義よりも厳密にはあまり役に立ちません。

+5

注意「も」:参加はバインドの用語で定義することができなかった場合、それは 'Monad'のメンバーであることを_have_う(またはすべてのモナドに対して定義されることはありません)、そうではありません。 –

答えて

9

ことが可能です:

join :: Monad m => m (m a) -> m a 
join m = (m >>= id) 

>>=のトリッキーなインスタンス化:

(>>=) :: m b -> (b -> m c) -> m c 
-- choosing b ~ m a , c ~ a 
(>>=) :: m (m a) -> (m a -> m a) -> m a 

ので、我々は正しく秒間idを選択することができます引数。

6

はい、それはかなり簡単です:

join m = m >>= id 
3

バインド(>>=)は実際にない「レイヤーを削除」:

(>>=) :: Monad m => m a -> (a -> m b) -> m b 

は、直感的には、「m aのうちのいくつかa Sを取得」、およびa -> m b関数に、その後フィード、そして単一の生成結果からm b

通常、出力はmに再び出力されますが、実際にはそうではありません。関数の出力をにする必要があります。何かがmにラップされていますが、折り返しがどこから来たかは関係ありません。

joinを実装する場合は、「double-wrapped」から始めることになります:m (m a)。私たちは、バインドのための署名にそれをプラグインして、すぐに「ダブル・ラップ」値のバインド時に私たちが使用できる機能の種類を把握することができます:

m (m a) -> (m a -> m b) -> m b 

が今ここにバインドで使用される関数が値を受け取るために起こっているのそれはです。はすでにmにラップされています。だから私たちは何かを "再ラップする"必要はありません。我々がそれを戻さなければ、それはすでに出力のための正しいタイプになるでしょう。効果的には、「ラッピングの1つのレイヤーが削除されました」 - これは最後のレイヤー以外のレイヤーでも機能します。

だから、私達はちょうどidと結合する必要が教えてくれる:

join = (>>= id) 
関連する問題