假设我想将列表的所有元素添加到但不包括第一个负数并返回列表的其余数。这样做的简单方法是
addpos l = s` seq`(s,back) 在哪里 (正面,背面)=跨度(> = 0)l S =总前方
seq
应确保没有人意外地通过将背部迫使后背构建巨大的地方。
我很好奇,但是,GHC是否足够聪明,可以避免创建中间前部列表。另外,有人可以解释一下(如果有的话)如何确定它可以严格积累?前奏定义使用foldl而不是foldl',而GHC定义看起来等效。
我们谈论编译器优化的中间列表时,通常我们在谈论在GHC的RULES
Pragma中实现的"融合";您可以在此处放心,以及哪个列表功能是"好的消费者"one_answers"生产者"。
不幸的是,它看起来不像span
是"好生产者"。您可以通过要求查看GHC的核心输出并获取用ghc -O2 -ddump-simpl -dsuppress-module-prefixes -dsuppress-uniques -ddump-core-stats -ddump-inlinings -ddump-rule-firings test.hs
这是一个已清理的输出:
Rule fired: Class op >=
Rule fired: SPEC Data.List.sum
Inlining done: geInt{v r3n} [gid]
Inlining done: sum_sum1{v rkV} [gid]
Inlining done: span{v r1Q} [gid]
Inlining done: sum_sum'1{v rl6} [gid]
==================== Tidy Core ====================
Result size of Tidy Core = {terms: 24, types: 27, coercions: 0}
addPos1 :: Int -> Bool
addPos1 = (ds :: Int) -> case ds of _ { I# x -> >=# x 0 }
addPos [InlPrag=INLINE[0]] :: [Int] -> (Int, [Int])
addPos =
(w :: [Int]) ->
case $wspan @ Int addPos1 w of _ { (# ww1, ww2 #) ->
case $wsum' ww1 0 of ww3 { __DEFAULT -> (I# ww3, ww2) }
}
您可以看到我们调用某种重写/专业的span
,然后是sum
。
您可能会查看vector
库是否可以融合它们,或者查看性能比较有趣的。