换句话说,可以将以下内容优化为Just [1..]
吗?
> sequence (map Just [1..])
*** Exception: stack overflow
data61/fp-course
中还有一个更具体的示例,如果存在Empty
值,则会提前终止。
seqOptional ::
List (Optional a)
-> Optional (List a)
seqOptional =
foldRight f (Full Nil)
where
f Empty _ = Empty
f _ Empty = Empty
f (Full a) (Full as) = Full (a :. as)
为什么改变前两个模式的顺序使函数循环永远,就好像Empty
不能匹配一样?我隐约明白,这样的定义会使f
在无限列表中变得严格,但我不知道究竟是什么导致了这一点。
或者这些无关的问题是什么?
附带问题:堆栈耗尽而不是堆是否重要?
答案 0 :(得分:3)
即使可以,也不应该。与@ user2407038的评论一样,根据Haskell的denotational semantics,sequence (map Just [1..])
表示与Just [1..]
不同的值。
Haskell函数是连续,这是精确推理无限数据结构的关键工具。为了说明连续性意味着什么,假设我们有一个越来越明确的无限值序列,例如:
⟂
1:⟂
1:2:⟂
1:2:3:⟂
现在,为每个人应用一个函数,让我们说tail
:
tail ⟂ = ⟂
tail (1:⟂) = ⟂
tail (1:2:⟂) = 2:⟂
tail (1:2:3:⟂) = 2:3:⟂
⋮ ⋮
tail [1..] = [2..]
函数连续的意思是,如果将函数应用于参数序列的 limit ,则得到序列的 limit 结果,如最后一行所示。
现在对部分定义的列表中的sequence
进行了一些观察:
-- a ⟂ after a bunch of Justs makes the result ⟂
sequence (Just 1 : Just 2 : ⟂) = ⟂
-- a Nothing anywhere before the ⟂ ignores the ⟂ (early termination)
sequence (Just 1 : Nothing : ⟂) = Nothing
我们只需要第一次观察。我们现在可以问你的问题:
sequence (map Just ⟂) = sequence ⟂ = ⟂
sequence (map Just (1:⟂)) = sequence (Just 1 : ⟂) = ⟂
sequence (map Just (1:2:⟂)) = sequence (Just 1 : Just 2 : ⟂) = ⟂
⋮ ⋮ ⋮
sequence (map Just [1..]) = ⟂
通过连续性,sequence (map Just [1..]) = ⟂
。如果你"优化"它给出了不同的答案,优化是不正确的。
答案 1 :(得分:0)
我无法回答你的第二个问题,但可以回答你的第一个问题。
理论上,编译器可以检测和优化这样的情况,但由于停机问题,它无法检测此模式的每个实例。它可以做的最好的是一堆临时启发式,我认为如果程序的终止取决于是否触发了特定的重写规则,那将更加令人困惑。