说我写了以下amazin代码:
func = do
a <- Just 5
return a
Run Code Online (Sandbox Code Playgroud)
我知道,这是毫无意义的.在这里,a是5,并func返回Just 5.
现在我重写了我很棒的(但没有意义的)功能:
func' = do
a <- Nothing
return a
Run Code Online (Sandbox Code Playgroud)
这个函数返回了Nothing,但到底是a什么?没有什么可以从一个Nothing值中提取,但是当我做这样的事情时,程序不会抱怨:
func'' = do
a <- Nothing
b <- Just 5
return $ a+b
Run Code Online (Sandbox Code Playgroud)
我只是很难看到实际发生的事情.什么是a?换句话说:<- 实际上做了什么?说它"从右侧提取值并将其绑定到左侧"显然过度简化了它.什么是我没有得到的?
谢谢 :)
Sar*_*rah 11
让我们试着去除最后一个例子的记号.
func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b))
Run Code Online (Sandbox Code Playgroud)
现在,让我们看看如何为Maybe定义>> =.它在前奏中:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= k = Nothing
return = Just
fail s = Nothing
Run Code Online (Sandbox Code Playgroud)
所以Nothing >>= foo很简单Nothing
答案在于以下Monad实例的定义Maybe:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
(Just _) >> k = k
Nothing >> _ = Nothing
return = Just
Run Code Online (Sandbox Code Playgroud)
您的func''翻译为:
Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b))))
Run Code Online (Sandbox Code Playgroud)
从(>>=)你的定义可以看出,第一个Nothing只是通过线索到结果.
我们来看看Maybemonad 的定义.
instance Monad Maybe where
return = Just
Just a >>= f = f a
Nothing >>= _ = Nothing
Run Code Online (Sandbox Code Playgroud)
并且do在你的函数中desugar -notation:
func' =
Nothing >>= \a ->
return a
Run Code Online (Sandbox Code Playgroud)
第一个参数>>=是Nothing,从上面的定义我们可以看到,>>=只是忽略了第二个参数.所以我们得到:
func' = Nothing
Run Code Online (Sandbox Code Playgroud)
由于\a -> ...永远不会调用该函数,因此a永远不会被赋值.所以答案是:a甚至没有达成.
至于desugaring do-notation,这里有一个快速描绘它是如何完成的(我做了一个简化 - 处理fail,即不匹配的模式):
do {a; rest} ? a >> do rest
Run Code Online (Sandbox Code Playgroud)
注意,>>通常用>>=as实现a >>= \_ -> do rest(即第二个函数只是忽略参数).
do {p <- a; rest} ? a >>= \p -> do rest
do {let x = a; rest} ? let x = a in do rest
Run Code Online (Sandbox Code Playgroud)
最后:
do {a} = a
Run Code Online (Sandbox Code Playgroud)
这是一个例子:
main = do
name <- getLine
let msg = "Hello " ++ name
putStrLn msg
putStrLn "Good bye!"
Run Code Online (Sandbox Code Playgroud)
desugars:
main =
getLine >>= \name ->
let msg = "Hello " ++ name in
putStrLn msg >>
putStrLn "Good bye!"
Run Code Online (Sandbox Code Playgroud)
为了让那些好奇的人完整,这里是"正确"的翻译do {p <- a; rest}(直接来自Haskell报告):
do {pattern <- a; rest} ? let ok pattern = do rest
ok _ = fail "error message"
in a >>= ok
Run Code Online (Sandbox Code Playgroud)