一番の答えは間違いなく正しく、タイプだけですばやく効率的に機能します。Haskellが得意になったら(免責事項:私はそうではありません)、これは関数定義をざっと読むよりもはるかに効率的にこれを理解する方法です。
しかし、最近、モナドチャレンジapに取り組んでいる間、まさにこの問題に苦労しなければならなかったので、それがいくつかの追加の直感を提供するかもしれないので、私は私の経験を共有することにしました。
まず、Monad Challengesが尋ねるのと同じように、この名前bindを使用してプライマリMonad演算子を参照し>>=ます。これは大いに役立つと思います。
独自のバージョンを定義すると、次のliftM2ことができます。
liftM2 :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c
liftM2 f ma mb =
ma `bind` \a ->
mb `bind` \b ->
return $ f a b
apこれを使って作成したいと思います。関数をしばらくそのままにして、に適切な関数を選択したと仮定してf、これがどのように機能するかを考えてみましょう。apf
上記の最初の部分である部分として、関数値のモナドを渡すと仮定しmaます。Just (+3)それは、または[(+3), (*2)]-モナドコンテキスト内に存在するいくつかの「関数」のようなものである可能性があります。
そして、引数値のモナドを2番目の部分として提供しますmb。たとえば、Just 5または[6,7,8]-モナドコンテキストに存在する「値」は、内部に存在する関数の引数として機能しますma。
その後、私たちは持っているだろう
liftM2 f (m someFunction) (m someArgument) =
(m someFunction) `bind` \a ->
(m someArgument) `bind` \b ->
return $ (f a b)
そして、に続くラムダ関数の内部では、それがそうなること、そしてそうなることbindを知っています-それが何をするかです:それは、そのモナドに固有の特別な処理を法として、モナドコンテキストからの値の抽出をシミュレートします。asomeFunctionbsomeArgumentbind
そのため、最終行は実際に
return $ f someFunction someArgument
さて、一歩下がって、作成の目標はモナドコンテキストの内部をap呼び出すことであることを思い出してください。したがって、yieldの使用が何であれ、関数適用の結果である必要があります。someFunctionsomeArgumentreturnsomeFunction someArgument
では、どうすれば2つの式を等しくすることができますか
f someFunction someArgument ==? someFunction someArgument
さて、それなら私たちは次のようなx = (someFunction someArgument)関数を探していますf
f x = x
fしたがって、それが必要であることがわかりますid。
最初に戻ると、これは私たちが探していることを意味しますliftM2 id。
基本的に、が操作可能な関数である場合はそうするliftM2 id ma mbつもりだと言っていますが、モナドコンテキスト内で結果を返しながら、「そのままにして」、その処理を実行します。m (id a b)abidab
それは、私たちliftM2が傍観者の偏見を強いられたようなものです。
そして、それがうまくいくためにaは、「TypeOfb」から「SomeReturnType」に変わる関数型、またはTypeOfb -> SomeReturnType、bがa期待される引数である必要があります。そしてもちろんb持っている必要がありTypeOfbます。
表記の乱用を1回許可する場合は、任意に記号「a」を使用して「TypeOfb」を表し、記号「b」を使用して「SomeReturnType」を表します。
`b` --> "a" is its type
`a` --> "a -> b" is its type
その場合、の型アノテーションは次のようにapなります。
ap :: Monad m => m (TypeOfB -> SomeReturnType) -> m TypeOfB -> m SomeReturnType
==>
ap :: Monad m => m (a -> b) -> m a -> m b