haskell 中 Monads 的 >> 运算符通常定义为
(>>) :: m a -> m b -> m b
a >> b = a >>= \_ -> b
它可以用来打印类似的东西
main = putStr "foo" >> putStrLn "bar"
为什么编译器不优化 的值putStr "foo"
而只是评估putStrLn "bar"
?它不需要它,为什么要计算它?
haskell 中 Monads 的 >> 运算符通常定义为
(>>) :: m a -> m b -> m b
a >> b = a >>= \_ -> b
它可以用来打印类似的东西
main = putStr "foo" >> putStrLn "bar"
为什么编译器不优化 的值putStr "foo"
而只是评估putStrLn "bar"
?它不需要它,为什么要计算它?
正如克里斯所说,这取决于单子。Identity
或者Reader
不会评估 前面的部分>>
,因为他们不需要它来计算结果。其他单子,如Writer
, Maybe
, Either
,State
或IO
will。
让我们Maybe
举个例子。>>=
定义为
Nothing >>= _ = Nothing
(Just x) >>= f = f x
所以如果我们扩展>>
我们得到
Nothing >> _ = Nothing
(Just x) >> y = y
因此Maybe
必须评估前面的内容>>
以查看结果是否为Nothing
或y
。
IO
特意以某种方式定义动作,以便评估是否需要其结果(否则将无法使用)。
嗯?当然它需要 的值putStr "foo"
。它被评估>>=
- 如果您想将 monad 视为动作,则仅丢弃动作的结果,而不是动作本身。
例如在解析器中,这意味着丢弃刚刚解析的序列 - 但它仍然被解析,所以光标仍在向前移动。
这取决于单子。在 IO 中被评估。在 Identity 中,第一个不被评估:
> import Control.Monad.Identity
> import Control.Monad.Trace
> let x = trace "x" $ return () :: Identity ()
> let y = trace "y" $ return () :: Identity ()
> runIdentity $ x >> y
y
()