也许monad建设

时间:2014-10-07 16:11:45

标签: haskell monads maybe

我目前正在努力应对Haskell的新元素:Monads。因此,我通过创建(>>=)运算符的示例向我介绍了这个运算符,该运算符仅在Maybe类型上执行函数(将其实际整数值作为其参数),只有它不相等到Nothing,否则返回Nothing

(>>=) :: 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))

在我看来,(>>=)运算符只需要一个Maybe值和一个返回一个的函数,但是在这个示例中,使用代码看起来像是它的两倍{ {1}}值和一次函数。但有人告诉我,它会评估Maybe,将结果放在x中,然后评估n,将结果放入y,然后执行y两者兼顾。虽然我不知道safediv运营商在这里扮演什么角色;这是如何运作的?

3 个答案:

答案 0 :(得分: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并执行(第二次>> =
      • savediv n m返回结果 - 你的关闭时仍然有n

在其他任何地方返回Nothing

所以(>>=)只是帮助你解构。

也许以do形式阅读和理解更容易:

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

这只是(>>=)

周围的语法糖

让我们追逐案例:

1. eval x = Nothingeval y = Nothing
eval x >>= (...) = Nothing >>= (...) = Nothing
2. eval x = Nothingeval y = Just n

这是一样的:

eval x >>= (...) = Nothing >>= (...) = Nothing
3. eval x = Just neval y = Nothing
eval x >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> eval y >>= (...)) 
= Just n >>= (\n -> Nothing)
= Nothing
4. eval x = Just neval 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

答案 1 :(得分: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

答案 2 :(得分:0)

你有

eval (Val n) = Just n

由此我们得出结论:eval产生Maybe值。第二个等式,让它重写为

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

eval (Div x y) = 
  eval x >>= g 
             where
             g n =  eval y >>= h 
                               where
                               h m =  safediv n m

请参阅?每个>>=应用程序中只涉及一个函数。在顶部,它是g。但g定义了 - 并使用 - h,因此h的正文可以访问其参数mg&#39 ; s论点,n

如果eval x生成Nothing,那么根据eval x >>= g类型的Nothing定义,>>=会立即Maybe Nothing >>= _ = Nothing),并且不会尝试eval y

但是如果它是(Just ...)那么它的值只被馈送到绑定函数(Just x >>= f = f x)。

因此,如果两个eval生成Just ...个值,则safediv n m会在范围内调用,nm都可以访问。它的可能定义为

safediv :: Num a => a -> a -> Maybe a
safediv n m | m == 0    =  Nothing
            | otherwise =  Just (div n m)    -- or something

所以h :: m -> Maybe mg :: n -> Maybe n以及类型适合,

-- assuming a missing type of "expressions", `Exp a`,
eval :: Num a => Exp a ->                                       Maybe a    
  -- Num a is assumed throughout, below
  eval (Div x y) =                                           -- Maybe a
  -- Maybe a >>= a ->                                           Maybe a
      eval x >>= g 
                 where
  --               a ->                                         Maybe a
  --                   Maybe a >>= a ->                         Maybe a 
                 g n =  eval y >>= h
                                   where
  --                                 a ->                       Maybe a
                                   h m =  safediv    n    m  -- Maybe a
  --                                      safediv :: a -> a ->  Maybe a

根据Maybe monad的绑定类型,

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