繁体   English   中英

也许monad建设

[英]Maybe monad construction

我目前正在努力寻找Haskell的新元素:单子。 因此,我通过创建一个(>>=)运算符的例子向我介绍了这个运算符,该运算符在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值和一个返回一个的函数,但是在这个示例中,使用代码看起来像是一个Maybe值和一次函数。 但是我被告知,它将对x求值,将结果safediv n ,然后对y求值,将结果safediv y ,然后对两者都执行safediv函数。 尽管我在这里看不到(>>=)运算符如何发挥作用; 这是如何运作的?

您可以这样阅读:

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

当你想做eval (Div xy)然后

  • 第一次eval x
    • 如果是Just n (使用第一个>> =
    • 然后取n并看看eval y (使用第一个>> =
      • 如果最后一个是Just m (第二个>> =
      • 然后拿m并做一个(第二个>> =
      • savediv nm返回它的结果 - 你仍然有你的关闭n

在以往其他CAES回到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

让我们做元素追逐来说明它是如何工作的。 如果我们有

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

你有

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的参数n

如果eval x产生Nothing ,则根据Maybe类型的>>=定义( Nothing >>= _ = Nothing ),立即eval x >>= g只是Nothing ,并且不会尝试eval y

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

因此,如果两个eval产生Just ...值,则在可访问参数nm的范围内调用safediv 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM