折叠、函数组合、单子和惰性,天哪?
我很困惑。我可以这样写:
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
是 f 的一元类似物。 g,但它们显然不像我想象的那么相似。你能解释一下为什么吗?
I am puzzled. I can write this:
import Control.Monad
main = print $ head $ (foldr (.) id [f, g]) [3]
where f = (1:)
g = undefined
and the output is 1
. That makes sense, because it reduces to:
main = print $ head $ ((1:) . undefined . id) [3]
main = print $ head $ (1:) ((undefined . id) [3])
main = print $ head $ 1 : ((undefined . id) [3])
main = print $ 1
But if I use a vaguely similar monadic technique, it doesn't work the same:
import Control.Monad
main = print $ (foldr (<=<) return [f, g]) 3
where f = const Nothing
g = undefined
This hits prelude.Undefined
. Which is odd, because I would expect it to reduce:
main = print $ ((const Nothing) <=< undefined <=< return) 3
main = print $ return 3 >>= undefined >>= (\_ -> Nothing)
main = print $ Nothing -- nope! instead, undefined makes this blow up
However, flipping the order of composition:
import Control.Monad
main = print $ (foldr (>=>) return [f, g]) 3
where f = const Nothing
g = undefined
does accomplish the expected short-circuiting and produces Nothing
.
main = print $ (const Nothing >=> undefined >=> return) 3
main = print $ (const Nothing 3) >>= undefined >>= return
main = print $ Nothing >>= undefined >>= return
main = print $ Nothing
I suppose comparing the two approaches might have been comparing apples and oranges, but can you explain the difference? I thought that f <=< g
was the monadic analogue to f . g
, but they are apparently not as analogous as I thought. Can you explain why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这取决于您正在使用哪个 monad,以及它的
(>>=)
运算符是如何定义的。在
Maybe
的情况下,(>>=)
在第一个参数中是严格的,正如 Daniel Fischer 所解释的那样。以下是一些其他单子的一些结果。
身份:懒惰。
IO:严格。
读者:懒惰。
作家:既有惰性变体又有严格变体。
状态:也有严格版本和惰性版本。
继续:严格。
It depends on which monad you're working with, and how its
(>>=)
operator is defined.In the case of
Maybe
,(>>=)
is strict in its first argument, as Daniel Fischer explained.Here are some results for a handful of other monads.
Identity: Lazy.
IO: Strict.
Reader: Lazy.
Writer: Has both a lazy and a strict variant.
State: Has also both a strict and a lazy version.
Cont: Strict.
Maybe
的绑定在第一个参数中是严格的。因此,当您尝试
点击
时,实现需要找出
undefined v
是Nothing
还是Just Something
来查看的等式(>>=)
使用。另一方面,
无需查看
(>>=)
的第二个参数即可确定结果。The bind for
Maybe
is strict in the first argument.So when you try
you hit
and the implementation needs to find out whether
undefined v
isNothing
orJust something
to see which equation of(>>=)
to use.On the other hand,
determines the result without looking at the second argument of
(>>=)
.