Haskell:(也许)monad构建

我目前正在用Haskell的一个新元素Monads来挣扎。 因此,我通过创建一个>> =运算符的例子来介绍这一点,该运算符在可能类型上执行一个函数(仅将其实际整数值作为它的参数),只要它不等于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的函数,但是在这个示例中,使用代码看起来好像它需要2次可能值和一次函数。 然而,我被告知它评估x,将结果放入n,然后评估y,将结果放入y中,然后对两者执行safediv函数。 虽然我没有看到(>> =)运算符在这里扮演什么角色, 这个怎么用?

如果有人能帮我解决这个问题,我会非常感激。

提前致谢!

最好的问候,Skyfe。


你可以这样读取它:

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从封闭!
  • 在其他的地方还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
    

    看到? y >>= hg内完成,在其参数n的范围内。 由eval x >>= g生成的n(Just some_n) >>= g

    如果eval x产生Nothing ,那么eval x >>= g只是Nothing ,立即根据>>=定义为Maybe的类型( Nothing >>= _ = Nothing ),以及没有eval y将尝试。

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

    因此,如果两个eval s都生成Just ...值,则safediv nm将在可以访问参数nm的范围内调用。

    我想它被定义为

    safediv n m | m == 0 = Nothing
        | otherwise = Just (div n m)  -- or something
    

    所以h :: m -> Maybe mg :: n -> Maybe n和类型符合(>>=) :: (Maybe a) -> (a -> Maybe b) -> (Maybe b)

    链接地址: http://www.djcxy.com/p/43367.html

    上一篇: Haskell : (maybe) monad construction

    下一篇: Difference between Monad and Applicative in Haskell