在某些向量操作中没有懒惰

时间:2014-07-05 09:30:10

标签: haskell

此代码试图热切地评估导致无限循环的[1..]

import qualified Data.Vector as V

infiniteLoop = V.zipWith (+) (V.fromList [1..4]) (V.fromList [1..])

为什么会这样?

2 个答案:

答案 0 :(得分:8)

使用-O2进行编译。

......好吧这只适用于某些情况。

unoptimised版本中,首先构建通过fromList创建的两个向量。由于向量是脊椎严格的(并且是未装箱的超限),因此无法构造无限大小的向量,因此会失败。

如果使用-O2进行编译,stream fusion就会发挥作用。现在,根本不创建所有中间向量(来自fromList的向量)。由于zipWith在第一次提供数据后停止,因此您现在具有终止功能。

但总的来说:不要将无限大小的耗材与向量运算一起使用,函数的语义现在取决于你的优化级别,这很糟糕。

原始"stream fusion" paper描述了从列表到流的切换,再次回到列表。为简化起见,您可以将列表视为向量(因为向量会添加一些额外的内容,如内存分配,monadic行为等)。

通常(并且简化得很多),重写规则用于在内部将矢量表示为流,启用融合,然后将流转换回矢量。

答案 1 :(得分:5)

Data.Vector.fromList为documented需要O(N)时间。在这里,您提供了无限数量的项目,因此需要无限的时间才能完成。

为什么不能懒惰地构造向量:它们对其他操作(获取,删除,长度,索引......)保证良好的性能,这需要使用知道存在多少元素的数据结构。 / p>