9

関数がモナドになる方法を理解するのに苦労しています。

関数は、 :(->) rの宣言によるとモナドです。Control.Monad.Instances

instance Monad ((->) r) where  
    return x = \_ -> x  
    h >>= f = \w -> f (h w) w  

MiranLipovačaがそれについて言っていることでさえ、私を混乱させます:

の実装>>=は少しわかりにくいようですが、実際にはそれだけではありません。を使用>>=して関数にモナディック値をフィードすると、結果は常にモナディック値になります。したがって、この場合、関数を別の関数にフィードすると、結果も関数になります。そのため、結果はラムダとして始まります。これまでのすべての実装は >>=、常に何らかの形で結果をモナディック値から分離し、関数fをその結果に適用していました。ここでも同じことが起こります。関数から結果を取得するには、それを何かに適用する必要があります(h w)。そのため、ここでは関数から結果を取得し、それにfを適用します。fは、この場合の関数であるモナディック値を返すため、wにも適用します。

(>> =)の型アノテーションは次のとおりです:(>> =):: ma->(a-> mb)-> mb

だから私はそれhがとタイプされているm aと思います。関数がの場合、型の値を返しますか?またはそれはタイプを取る何か他のものを返しますか?f(a -> m b)m aaa

の非モナド値hがに供給されるとf、次のようになります。f(hw)問題ないように見えます。fは関数であり、その唯一の引数を取っているので、それはすでに値ですよね?これはモナディック関数であるため、値もモナディック値です。では、なぜ別の値が必要なのですwか?それを非モナディックにするために餌wを与えていませんか?つまり、それはもはや機能ではありませんか?また、理由をf something理解できず、同じ引数を取り、異なる値型(および)を返します。f somethinghwm am b

4

2 に答える 2

12

まず、次のタイプがあり(>>=)ます:

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

今、にm特化して((->) r)

(>>=) :: ((->) r) a -> (a -> ((->) r) b) -> ((->) r) b

すべての関数矢印を中置して書き直しました:

(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)

余分な括弧を削除する:

(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b

その時点で、何が起こっているのかを確認するのがはるかに簡単になるはずです。(タイプのr)3番目の引数が最初の引数に与えられてタイプの何かを取得しa、次にその結果と3番目の引数の両方が2番目の引数に与えられてタイプの最終結果b

したがって、((->) r)aMonadはそのモナド内のすべての値に対する追加の関数引数を表し、モナド値が結合されると、単一の「追加」引数が複製され、各入力値に与えられます。基本的に、これにより、モナディック値の「読み取り専用のグローバル環境」が作成されます。この解釈は、モナドとして明示的に提供されます。Readerモナドは、の単なるラッパー((->) r)です。

于 2012-10-26T03:11:24.347 に答える
6

モナドは。の代わりにとjoinを使用して同等に定義できるため、何が行われるかを確認することで、このモナドを理解するのはおそらく簡単です。fmapjoin>>=

の一般的な形式はjoinタイプを持っているMonad m => m (m b) -> m bので、「2層」のモナディック値を取り、それを1つの層にクランチします。

関数モナドでは、、は型を持っているm ~ (a ->)ので、2つの引数の関数を取り、1つだけを取る関数を返します。join(a -> a -> b) -> (a -> b)

join :: (a -> a -> b) -> (a -> b)
join f = \x -> f x x

ご覧のとおり、引数を複製しているだけです。

同様に、fmapon関数は単なる関数合成であり、returnですconst

を理解しようとするよりも、この方法を理解する方がはるかに簡単だと思います>>=

于 2012-10-26T03:10:24.780 に答える