[英]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
这只是语法糖(>>=)
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
让我们做元素追逐来说明它是如何工作的。 如果我们有
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
的主体可以访问其参数m
和g
的参数n
。
如果eval x
产生Nothing
,则根据Maybe
类型的>>=
定义( Nothing >>= _ = Nothing
),立即eval x >>= g
只是Nothing
,并且不会尝试eval y
。
但是,如果它是(Just ...)
那么它的值将被馈送到绑定函数中( Just x >>= f = fx
)。
因此,如果两个eval
产生Just ...
值,则在可访问参数n
和m
的范围内调用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 m
和g :: 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.