在一些向量操作中没有惰性

  • 本文关键字:操作 向量 haskell
  • 更新时间 :
  • 英文 :


这段代码尝试急切求值[1..],这会导致一个无限循环。

import qualified Data.Vector as V
infiniteLoop = V.zipWith (+) (V.fromList [1..4]) (V.fromList [1..])

为什么会这样?

-O2编译

…这只在某些情况下有效。

unoptimised构建中,首先构建通过fromList创建的两个向量。因为向量是脊严格的(而非盒装的是超严格的),这将失败,因为你不能构造一个无限大小的向量。

如果使用-O2编译,则使用stream fusion。现在,所有中间向量(来自fromList的那些)都不会被创建。由于zipWith在完成第一次数据提供后停止,因此现在有了一个终止函数。

但一般来说:不要使用无限大小的供应向量操作,你的函数的语义现在取决于你的优化水平,这是不好的。

最初的"流融合"论文描述了从列表到流,再回到列表的转换。为了简化,你可以把列表想象成向量(因为向量增加了一堆额外的东西,比如内存分配,一元行为,…)。

一般情况下(并且非常简化),重写规则用于在内部将向量表示为流,启用融合,然后将流转换回向量。

Data.Vector.fromList被记录为耗时O(N)。在这里,您提供了无限数量的物品,因此需要无限的时间来完成。

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

最新更新