mapM return [1..]
这是一个不会终止的证明的尝试。让我们暂时假设我们在Identity
monad 中(这个论点也适用于任何其他 monad):
mapM return [1..] -- initial expression
sequence (map return [1 ..]) -- unfold mapM
let k m m' = m >>= \x ->
m' >>= \xs ->
return (x : xs)
in foldr k (return []) (map return [1..]) -- unfold sequence
到目前为止,一切都很好...
-- unfold foldr
let k m m' = m >>= \x ->
m' >>= \xs ->
return (x : xs)
go [] = return []
go (y:ys) = k y (go ys)
in go (map return [1..])
-- unfold map so we have enough of a list to pattern-match go:
go (return 1 : map return [2..])
-- unfold go:
k (return 1) (go (map return [2..])
-- unfold k:
(return 1) >>= \x -> go (map return [2..]) >>= \xs -> return (x:xs)
回想一下,return a = Identity a
在 Identity monad 和(Identity a) >>= f = f a
Identity monad 中。继续:
-- unfold >>= :
(\x -> go (map return [2..]) >>= \xs -> return (x:xs)) 1
-- apply 1 to \x -> ... :
go (map return [2..]) >>= \xs -> return (1:xs)
-- unfold >>= :
(\xs -> return (1:xs)) (go (map return [2..]))
请注意,此时我们很想申请\xs
,但我们还不能!相反,我们必须继续展开,直到我们有一个可以应用的值:
-- unfold map for go:
(\xs -> return (1:xs)) (go (return 2 : map return [3..]))
-- unfold go:
(\xs -> return (1:xs)) (k (return 2) (go (map return [3..])))
-- unfold k:
(\xs -> return (1:xs)) ((return 2) >>= \x2 ->
(go (map return [3..])) >>= \xs2 ->
return (x2:xs2))
-- unfold >>= :
(\xs -> return (1:xs)) ((\x2 -> (go (map return [3...])) >>= \xs2 ->
return (x2:xs2)) 2)
此时,我们仍然不能申请\xs
,但我们可以申请\x2
。继续:
-- apply 2 to \x2 :
(\xs -> return (1:xs)) ((go (map return [3...])) >>= \xs2 ->
return (2:xs2))
-- unfold >>= :
(\xs -> return (1:xs)) (\xs2 -> return (2:xs2)) (go (map return [3..]))
\xs
现在我们已经到了一个既不能也 \xs2
不能减少的地步!我们唯一的选择是:
-- unfold map for go, and so on...
(\xs -> return (1:xs))
(\xs2 -> return (2:xs2))
(go ((return 3) : (map return [4..])))
所以你可以看到,因为foldr
,我们正在构建一系列要应用的函数,从列表的末尾开始,然后按照我们的方式进行备份。因为在每一步输入列表都是无限的,这种展开永远不会终止,我们也永远不会得到答案。
如果您查看此示例,这是有道理的(从另一个 StackOverflow 线程借来的,我目前找不到哪个)。在以下单子列表中:
mebs = [Just 3, Just 4, Nothing]
我们希望sequence
捕获Nothing
并返回整个事情的失败:
sequence mebs = Nothing
但是,对于此列表:
mebs2 = [Just 3, Just 4]
我们希望序列给我们:
sequence mebs = Just [3, 4]
换句话说,sequence
必须查看整个单子计算列表,将它们串在一起,然后全部运行,才能得出正确的答案。没有sequence
看到整个列表就无法给出答案。
注意:此答案的先前版本断言foldr
从列表的后面开始计算,并且在无限列表上根本不起作用,但这是不正确的!如果您传递给的运算符foldr
在其第二个参数上是惰性的,并使用诸如列表之类的惰性数据构造函数生成输出,foldr
则将很高兴与无限列表一起使用。参见foldr (\x xs -> (replicate x x) ++ xs) [] [1...]
示例。但我们的 operator 并非如此k
。