这段代码尝试急切地计算[1..]
,这会导致无限循环。
import qualified Data.Vector as V
infiniteLoop = V.zipWith (+) (V.fromList [1..4]) (V.fromList [1..])
为什么会这样?
最佳答案
使用-O2
编译。
...好吧,这仅在某些情况下有效。
在您的未优化
构建中,首先构建通过fromList
创建的两个向量。由于向量是脊椎严格的(并且未装箱的向量是超严格的),因此这将失败,因为您无法构造无限大小的向量。
如果使用-O2
进行编译,流融合
就会发挥作用。现在,所有中间向量(来自 fromList
的向量)根本没有被创建。由于 zipWith
在第一次数据提供完成后停止,因此您现在有了一个终止函数。
但一般来说:不要在向量运算中使用无限大小的供应,函数的语义现在取决于您的优化级别,这是不好的。
原文"stream fusion" paper描述从列表到流的切换,以及再次返回列表的切换。为了简化起见,您可以将列表视为向量(因为向量添加了一堆附加内容,例如内存分配、单子(monad)行为等)。
一般来说(并且更加简单),重写规则用于在内部将向量表示为流,从而实现融合,然后流又转回向量。
关于haskell - 某些向量运算中没有惰性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24584986/