list - 出于效率原因,ghc 是否将仅使用一次的列表转换为生成器?

标签 list optimization haskell generator lazy-evaluation

如果是这样,这是标准的一部分还是我们可以依赖的 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/

相关文章:

opengl - 我如何处理 OpenGL 中的透视投影?

java - 链表 : infinite loop

python - 优化 bigint 调用

sql - 如何找出哪些 SQL 查询被阻止以及哪些内容阻止了它们?

swift - 原始类型的快速扩展性能

haskell - Haskell 函数类型声明中括号的详细信息

haskell - 如何让 GHC 相信递归类型的类型相等性

r - 如何将列表中的特定对象展开.grid以形成新列表

python - 列表列表到 numpy 数组中

wpf - 使用 binding-WPF 设置数据网格列号