23

我很困惑。我可以这样写:

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

但如果我使用一种模糊相似的单子技术,它的工作原理就不一样了:

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是 monadic 的类似物f . g,但它们显然不像我想象的那样类似。你能解释一下为什么吗?

4

2 回答 2

21

这取决于您正在使用哪个 monad,以及它的(>>=)运算符是如何定义的。

正如 Daniel Fischer 解释的那样,在 的情况下Maybe,它的第一个参数是严格的。(>>=)

以下是一些其他单子的一些结果。

> :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
于 2011-11-23T23:10:47.710 回答
19

第一个参数中的绑定Maybe是严格的。

Just v >>= f = f v
Nothing >>= f = Nothing

所以当你尝试

Just v >>= undefined >>= \_ -> Nothing

你打

undefined v >>= \_ -> Nothing

并且实现需要找出是否undefined v使用NothingJust something查看使用哪个方程(>>=)

另一方面,

Nothing >>= undefined

无需查看 的第二个参数即可确定结果(>>=)

于 2011-11-23T22:47:38.893 回答