2

私は現在、Haskell の新しい要素であるモナドに苦労しています。したがって、型が と等しくない場合にのみ (実際の整数値を引数として受け取る) 型(>>=)に対して関数を実行し、それ以外の場合は を返す演算子を作成する例によって、これを紹介しました。MaybeNothingNothing

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= _ = Nothing
(Just x) >>= f = f x

ただし、これが次の使用法でどのように機能するかはよくわかりません。

eval (Val n) = Just n
eval (Div x y) = eval x >>= (\n ->
    eval y >>= (\m ->
        safediv n m))

(>>=)演算子は単純に 1 つのMaybe値とそれを返す関数を受け取るように思えますが、この例の使用コードでは、値を 2 回、関数を 1 回取っているように見えますMaybexただし、 を評価し、結果を に入れn、次に を評価しy、結果を に入れ、両方で関数をy実行すると言われました。ここでオペレーターがどのようにその役割を果たすsafedivかはわかりませんが。(>>=)これはどのように作動しますか?

4

3 に答える 3

6

次のように読むことができます。

eval (Div x y) = eval x >>= (\n ->
    eval y >>= (\m ->
        safediv n m))

あなたがやりたいときeval (Div x y)

  • 最初eval x:
    • だった場合Just n(最初の>>=を使用)
    • 次に、nを見て見てくださいeval y(最初の>>=を使用)
      • 最後がJust m(秒>>= )の場合
      • 次に、を取り、m(2番目の>> =)を実行します
      • savediv n mnその結果を返すには、クロージャからまだあります!.

他のケースでは戻りますNothing

したがって、ここでは、(>>=)分解するのに役立ちます。

do次の形式の方が読みやすく、理解しやすいかもしれません。

eval (Val n) = Just n
eval (Div x y) = do
    n <- eval x
    m <- eval y
    safediv n m

これは単なる構文糖衣です(>>=)

ケースを追跡しましょう:

1.eval x = Nothingおよびeval y = Nothing:
eval x >>= (...) = Nothing >>= (...) = Nothing
2.eval x = Nothingおよびeval y = Just n:

これはまったく同じです:

eval x >>= (...) = Nothing >>= (...) = Nothing
3.eval x = Just nおよびeval y = Nothing:
eval x >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> eval y >>= (...)) 
= Just n >>= (\n -> Nothing)
= Nothing
4.eval x = Just nおよびeval y = Just m:
eval x >>= (\n -> Just m >>= (...))
= Just n >>= (\n -> Just m >>= (...)) 
= Just n >>= (\n -> Just m >>= (\m -> safediv n m))
= (first >>= for Just) = Just m >>= (\n -> safediv n m)
= (second >>= for Just) = safediv n m
于 2014-10-07T16:17:14.913 に答える
1

それがどのように機能するかを説明するために、要素追跡を行いましょう。私たちが持っている場合

eval (Div (Val 5) (Div (Val 0) (Val 1)))

次に、これを次のように分解できます。

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = eval (Val 5) >>=
        (\n ->
            eval (Div (Val 0) (Val 1)) >>=
                (\m ->
                    safediv n m
                )
        )

-- eval (Val 5) = Just 5

    = Just 5 >>=
        (\n ->
            eval (Div (Val 0) (Val 1)) >>=
                (\m ->
                    safediv n m
                )
        )

-- Just x >>= f = f x

    = (\n ->
        eval (Div (Val 0) (Val 1)) >>=
            (\m ->
                safediv n m
            )
      ) 5

-- Substitute n = 5, since the 5 is the argument to the `\n ->` lamba

    = eval (Div (Val 0) (Val 1)) >>=
        (\m ->
            safediv 5 m
        )

ここで、計算するために迂回する必要がありeval (Div (Val 0) (Val 1))ます...

eval (Div (Val 0) (Val 1))
    = eval (Val 0) >>=
        (\n ->
            eval (Val 1) >>=
                (\m ->
                    safediv n m
                )
        )

-- eval (Val 0) = Just 0
-- eval (Val 1) = Just 1

eval (Div (Val 0) (Val 1))
    = Just 0 >>=
        (\n ->
            Just 1 >>=
                (\m ->
                    safediv n m
                )
        )

-- Just x >>= f = f x

eval (Div (Val 0) (Val 1))
    = (\n ->
        (\m ->
            safediv n m
        ) 1
      ) 0

    = (\n -> safediv n 1) 0
    = safediv 0 1
    = Just 0

そして、元の への呼び出しに戻り、次のようevalに置き換えJust 0ます。

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = Just 0 >>= (\m -> safediv 5 m)

-- Just x >>= f = f x

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = safediv 5 0

-- safediv x 0 = Nothing

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = Nothing
于 2014-10-07T16:36:44.717 に答える