为了提高效率,ghc是否只将一次使用的列表转换为生成器?

Rom*_*her 5 optimization haskell list 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..]
Run Code Online (Sandbox Code Playgroud)

嚼CPU但不消耗太多内存.

Dan*_*her 7

取决于您对发电机的意义.该列表是懒惰生成的,由于没有其他任何内容引用它,消耗的部分几乎立即被垃圾收集.由于上述计算的结果没有增长,整个计算在恒定的空间中运行.这不是标准规定的,但是因为在该示例中实现具有不同空间行为的非严格语义(以及许多模糊相似)更难实现,实际上您可以依赖它.

但通常情况下,列表仍然是作为列表生成的,因此产生了大量垃圾.在有利的情况下,ghc会删除列表[1 .. ]并生成一个非分配循环:

result :: [Int]
result = filter odd . filter even $ [1 .. ]
Run Code Online (Sandbox Code Playgroud)

(使用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
        }
    }
Run Code Online (Sandbox Code Playgroud)

一个普通的循环,从1到1运行maxBound :: Int,在路上和[]最后都没有产生任何结果.它几乎足够聪明,无法回归[].注意,只有一个除以2,GHC知道如果a Int是偶数,则它不能是奇数,因此检查已被消除,并且在没有分支的情况下创建非空列表(即,不可达的分支已被删除被编译器淘汰了).