Haskell 也许是单子结构
我目前正在与Haskell的一个新元素作斗争:单子。因此,我通过创建一个Haskell 也许是单子结构,haskell,monads,maybe,Haskell,Monads,Maybe,我目前正在与Haskell的一个新元素作斗争:单子。因此,我通过创建一个(>=)运算符的示例了解到这一点,该运算符仅在可能类型上执行函数(将其实际整数值作为参数),前提是该类型不等于Nothing,否则返回Nothing: (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b Nothing >>= _ = Nothing (Just x) >>= f = f x eval x >>= (.
(>=)
运算符的示例了解到这一点,该运算符仅在可能
类型上执行函数(将其实际整数值作为参数),前提是该类型不等于Nothing
,否则返回Nothing
:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= _ = Nothing
(Just x) >>= f = f x
eval x >>= (...) = Nothing >>= (...) = Nothing
eval x >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> Nothing)
= Nothing
但是,我不太清楚它在以下情况下是如何工作的:
eval (Val n) = Just n
eval (Div x y) = eval x >>= (\n ->
eval y >>= (\m ->
safediv n m))
在我看来,
(>>=)
操作符只需要取一个可能
值和一个返回值的函数,但是在本例中,使用代码似乎是取一个可能
值的2倍,一个函数取一次。但是,我被告知,它计算x
,将结果放入n
,然后计算y
,将结果放入y
,然后对这两个对象执行safediv
函数。虽然我不知道(>>=)
操作符是如何在这里发挥作用的;这是怎么回事 你可以这样读:
eval (Div x y) = eval x >>= (\n ->
eval y >>= (\m ->
safediv n m))
当你想做eval(Div x y)
- 第一次
:评估x
- if was
(使用第一个>=)只是n
- if was
- 然后使用
查看n
(使用第一个>=)eval y
- 然后使用
- 如果最后一个是
(第二个>=),只有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
2. <代码>评估x=无和评估y=仅n
:
这是一样的:
eval x >>= (...) = Nothing >>= (...) = Nothing
3. <代码>评估x=仅n和评估y=无
:
eval x >>= (...) = Nothing >>= (...) = Nothing
eval x >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> Nothing)
= Nothing
4. <代码>评估x=仅n和评估y=仅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(val0)(val1))
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
的调用,将仅替换为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
产生一个可能
值。第二个等式,我们重写为
eval (Div x y) =
eval x >>= (\n ->
eval y >>= (\m ->
safediv n m ) )
i、 e
看到了吗?每个>>=
应用程序中只涉及一个函数。在顶部,它是g
。但是g
定义并使用–h
,因此h
的主体可以访问其参数m
和g
的参数n
如果eval x
生成了Nothing
,那么eval x>=g
就是Nothing
,根据>=
可能类型的定义(Nothing>==Nothing
),立即,并且不会尝试eval y
但是如果它是(Just…
,那么它的值只会被输入到绑定函数中(Just x>=f=f x
)
因此,如果两个eval
s都产生Just…
值,则在可访问参数n
和m
的范围内调用safediv n m
。它可能被定义为
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 a ->
(a -> Maybe b) ->
Maybe b
(>>=)::可能是a->
(a->也许b)->
也许b
我也是这么想的,但是我不知道(>>=)函数是如何工作的,它使用了两次,第一次(我读取它的方式)使用一个值和另一个值,然后再次使用该值和一个函数的结果。然而,运算符只接受一个值和一个函数?@user2999349它只是用来先从“just n”中获取“n”,然后第二次从“just m”中获取“m”@user2999349它是两个独立的应用程序,>=
内部的应用程序有参数eval y
和(\m->safediv n m)
,而外部参数有as参数eval x
和(\n->eval y>>=(\m->safediv n m))