[英]Maybe monad construction
I'm currently struggling with a new element of Haskell: Monads. 我目前正在努力寻找Haskell的新元素:单子。 Therefore I was introduced to this by an example of creating a (>>=)
operator that executes a function on a Maybe
type (taking its actual integer value as argument to it) only if it's not equal to Nothing
, and otherwise return Nothing
: 因此,我通过创建一个(>>=)
运算符的例子向我介绍了这个运算符,该运算符在Maybe
类型上执行一个函数(将其实际的整数值作为参数),只有它不等于Nothing
,否则返回Nothing
:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= _ = Nothing
(Just x) >>= f = f x
However, I'm not quite sure how this works with the following usage of it: 但是,我不太确定它在以下用法下如何工作:
eval (Val n) = Just n
eval (Div x y) = eval x >>= (\n ->
eval y >>= (\m ->
safediv n m))
It seems to me that the (>>=)
operator simply takes one Maybe
value and a function that returns one, however in this example usage code it seems like it's taking 2 times a Maybe
value and once a function. 在我看来, (>>=)
运算符只需要一个Maybe
值和一个返回一个的函数,但是在这个示例中,使用代码看起来像是一个Maybe
值和一次函数。 I was told however that it evaluates x
, puts the result in n
, then evaluates y
, puts the result in y
, and then executes the safediv
function on both. 但是我被告知,它将对x
求值,将结果safediv
n
,然后对y
求值,将结果safediv
y
,然后对两者都执行safediv
函数。 Although I don't see how the (>>=)
operator plays its role here; 尽管我在这里看不到(>>=)
运算符如何发挥作用; How does this work? 这是如何运作的?
You can read it like this: 您可以这样阅读:
eval (Div x y) = eval x >>= (\n ->
eval y >>= (\m ->
safediv n m))
when you want do eval (Div xy)
then 当你想做eval (Div xy)
然后
eval x
: 第一次eval x
: Just n
(using the first >>= ) 如果是Just n
(使用第一个>> = ) n
and have a look at eval y
(using the first >>= ) 然后取n
并看看eval y
(使用第一个>> = ) Just m
(second >>= ) 如果最后一个是Just m
(第二个>> = ) m
and do a (second >>= ) 然后拿m
并做一个(第二个>> = ) savediv nm
to return it's result - you still have the n
from your closure!. savediv nm
返回它的结果 - 你仍然有你的关闭n
! in ever other caes return Nothing
在以往其他CAES回到Nothing
So here the (>>=)
just helps you to deconstruct. 所以这里(>>=)
只是帮助你解构。
Maybe it's easier to read and understand in the do
form: 也许在do
表单中阅读和理解更容易:
eval (Val n) = Just n
eval (Div x y) = do
n <- eval x
m <- eval y
safediv n m
which is just syntactic sugar around (>>=)
这只是语法糖(>>=)
eval x = Nothing
and eval y = Nothing
:
1. eval x = Nothing
, eval y = Nothing
:
eval x >>= (...) = Nothing >>= (...) = Nothing
2. eval x = Nothing
and eval y = Just n
:
2. eval x = Nothing
和eval y = Just n
:
which is just the same: 这是一样的:
eval x >>= (...) = Nothing >>= (...) = Nothing
3. eval x = Just n
and eval y = 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
and eval y = Just m
:
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
Let's do element chasing to illustrate how it works. 让我们做元素追逐来说明它是如何工作的。 If we have 如果我们有
eval (Div (Val 5) (Div (Val 0) (Val 1)))
Then we can break this down into 然后我们可以将其分解为
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
)
Now we need to take a detour to compute eval (Div (Val 0) (Val 1))
... 现在我们需要绕道计算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
And now back to our original call to eval
, substituting Just 0
in: 现在回到我们最初的调用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
you have 你有
eval (Val n) = Just n
from this we conclude that eval
produces a Maybe
value. 由此我们得出结论, eval
产生一个Maybe
值。 The second equation, let's rewrite it as 第二个等式,我们将其重写为
eval (Div x y) =
eval x >>= (\n ->
eval y >>= (\m ->
safediv n m ) )
ie 即
eval (Div x y) =
eval x >>= g
where
g n = eval y >>= h
where
h m = safediv n m
See? 看到? There is only one function involved in each >>=
application. 每个>>=
应用程序仅涉及一个功能。 At the top, it's g
. 在顶部,是g
。 But g
defines – and uses – h
, so h
's body has access both to its argument m
and the g
's argument, n
. 但是g
定义并使用了h
,因此h
的主体可以访问其参数m
和g
的参数n
。
If eval x
produced Nothing
, then eval x >>= g
is just Nothing
, immediately, according to the >>=
definition for the Maybe
types ( Nothing >>= _ = Nothing
), and no eval y
will be attempted. 如果eval x
产生Nothing
,则根据Maybe
类型的>>=
定义( Nothing >>= _ = Nothing
),立即eval x >>= g
只是Nothing
,并且不会尝试eval y
。
But if it was (Just ...)
then its value is just fed to the bound function ( Just x >>= f = fx
). 但是,如果它是(Just ...)
那么它的值将被馈送到绑定函数中( Just x >>= f = fx
)。
So if both eval
s produce Just ...
values, safediv nm
is called inside the scope where both arguments n
and m
are accessible. 因此,如果两个eval
产生Just ...
值,则在可访问参数n
和m
的范围内调用safediv nm
。 It's probably defined as 它可能被定义为
safediv :: Num a => a -> a -> Maybe a
safediv n m | m == 0 = Nothing
| otherwise = Just (div n m) -- or something
and so h :: m -> Maybe m
and g :: n -> Maybe n
and the types fit, 所以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
as per the type of bind for the Maybe monad, 根据Maybe monad的绑定类型,
(>>=) :: Maybe a ->
(a -> Maybe b) ->
Maybe b
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.