如果是这样,这是标准的一部分还是我们可以依赖的 ghc 特定优化?或者只是我们不一定依赖的优化。
PS:
当我尝试一个测试样本时,它似乎表明它正在发生/
Prelude> let isOdd x = x `mod` 2 == 1
Prelude> let isEven x = x `mod` 2 == 0
Prelude> ((filter isOdd).(filter isEven)) [1..]
消耗 CPU 但不消耗太多内存。
最佳答案
取决于您所说的生成器是什么意思。该列表是延迟生成的,并且由于没有其他内容引用它,因此消耗的部分几乎立即被垃圾收集。由于上述计算的结果没有增长,整个计算在恒定空间中运行。这不是标准强制要求的,但由于该示例更难实现具有不同空间行为的非严格语义(以及许多模糊相似的),因此在实践中您可以依赖它。
但是通常情况下,列表仍然是作为列表生成的,因此产生了很多垃圾。在有利的情况下,ghc 删除列表 [1 .. ]
并产生一个非分配循环:
result :: [Int]
result = filter odd . filter even $ [1 .. ]
(出于懒惰而使用 Prelude 函数),使用
-O2
编译生成核心List.result_go =
\ (x_ayH :: GHC.Prim.Int#) ->
case GHC.Prim.remInt# x_ayH 2 of _ {
__DEFAULT ->
case x_ayH of wild_Xa {
__DEFAULT -> List.result_go (GHC.Prim.+# wild_Xa 1);
9223372036854775807 -> GHC.Types.[] @ GHC.Types.Int
};
0 ->
case x_ayH of wild_Xa {
__DEFAULT -> List.result_go (GHC.Prim.+# wild_Xa 1);
9223372036854775807 -> GHC.Types.[] @ GHC.Types.Int
}
}
一个简单的循环,从 1 运行到
maxBound :: Int
,在途中什么也没产生和[]
在末尾。它几乎足够聪明,可以简单地返回
[]
.请注意,只有一个除以 2,GHC 知道如果 Int
是偶数,它不能是奇数,因此检查已被消除,并且在任何分支中都不会创建非空列表(即,编译器已消除了无法访问的分支)。
关于list - 出于效率原因,ghc 是否将仅使用一次的列表转换为生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8278077/