我很困惑。我可以这样写:
import Control.Monad
main = print $ head $ (foldr (.) id [f, g]) [3]
where f = (1:)
g = undefined
,输出为1
。这是有道理的,因为它减少到:
main = print $ head $ ((1:) . undefined . id) [3]
main = print $ head $ (1:) ((undefined . id) [3])
main = print $ head $ 1 : ((undefined . id) [3])
main = print $ 1
但是,如果我使用模糊相似的monadic技术,它的效果不一样:
import Control.Monad
main = print $ (foldr (<=<) return [f, g]) 3
where f = const Nothing
g = undefined
这会点击prelude.Undefined
。这很奇怪,因为我希望它能减少:
main = print $ ((const Nothing) <=< undefined <=< return) 3
main = print $ return 3 >>= undefined >>= (\_ -> Nothing)
main = print $ Nothing -- nope! instead, undefined makes this blow up
然而,翻转组成顺序:
import Control.Monad
main = print $ (foldr (>=>) return [f, g]) 3
where f = const Nothing
g = undefined
确实完成了预期的短路并产生Nothing
。
main = print $ (const Nothing >=> undefined >=> return) 3
main = print $ (const Nothing 3) >>= undefined >>= return
main = print $ Nothing >>= undefined >>= return
main = print $ Nothing
我想比较两种方法可能比较苹果和橙子,但你能解释一下这种差异吗?我认为f <=< g
是f . g
的monadic类似物,但它们显然不像我想象的那样类似。你能解释一下原因吗?
答案 0 :(得分:20)
这取决于您正在使用哪个monad,以及如何定义(>>=)
运算符。
在Maybe
的情况下,(>>=)
的第一个论点是严格的,正如Daniel Fischer解释的那样。
以下是少数其他monad的一些结果。
> :set -XNoMonomorphismRestriction
> let foo = (const (return 42) <=< undefined <=< return) 3
> :t foo
foo :: (Num t, Monad m) => m t
身份:懒惰。
> Control.Monad.Identity.runIdentity foo
42
IO:严格。
> foo :: IO Integer
*** Exception: Prelude.undefined
读者:懒惰。
> Control.Monad.Reader.runReader foo "bar"
42
作家:既有懒惰又有严格的变体。
> Control.Monad.Writer.runWriter foo
(42,())
> Control.Monad.Writer.Strict.runWriter foo
*** Exception: Prelude.undefined
状态:还有严格版和懒版版。
> Control.Monad.State.runState foo "bar"
(42,"*** Exception: Prelude.undefined
> Control.Monad.State.Strict.runState foo "bar"
*** Exception: Prelude.undefined
续:严格。
> Control.Monad.Cont.runCont foo id
*** Exception: Prelude.undefined
答案 1 :(得分:19)
Maybe
的绑定在第一个参数中是严格的。
Just v >>= f = f v
Nothing >>= f = Nothing
所以当你尝试
时Just v >>= undefined >>= \_ -> Nothing
你打了
undefined v >>= \_ -> Nothing
并且实施需要找出undefined v
是Nothing
还是Just something
,以查看要使用的(>>=)
等式。
另一方面,
Nothing >>= undefined
确定结果而不查看(>>=)
的第二个参数。