ghci 中内存消耗的原因不是filter
or的代码elem
。filter
(尽管in的重写规则GHC.List
通常使它更好一点。)
让我们看一下使用 ( ) 生成的核心 ghc-7.4.2 的(部分-O2
)-ddump-simpl
。首先r
,使用GHC.List.filter
:
Has.r1
:: GHC.Integer.Type.Integer
-> [GHC.Integer.Type.Integer] -> [GHC.Integer.Type.Integer]
[GblId,
Arity=2,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=2, Value=True,
ConLike=True, Cheap=True, Expandable=True,
Guidance=IF_ARGS [0 0] 60 30}]
Has.r1 =
\ (x_awu :: GHC.Integer.Type.Integer)
(r2_awv :: [GHC.Integer.Type.Integer]) ->
case GHC.Integer.Type.eqInteger x_awu Has.p5 of _ {
GHC.Types.False -> r2_awv;
GHC.Types.True ->
GHC.Types.: @ GHC.Integer.Type.Integer x_awu r2_awv
}
Has.r :: [GHC.Integer.Type.Integer]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, Cheap=False, Expandable=False,
Guidance=IF_ARGS [] 40 0}]
Has.r =
GHC.Enum.enumDeltaIntegerFB
@ [GHC.Integer.Type.Integer] Has.r1 Has.p3 Has.p2
Has.p3
是0 :: Integer
,并且Has.p2
是1 :: Integer
。重写规则 (for filter
and enumDeltaInteger
) 把它变成了 (用更短的名字)
r = go fun 0 1
where
go foo x d = x `seq` (x `foo` (go foo (x+d) d))
fun n list
| n == 1000000000000 = n : list
| otherwise = list
如果被内联,这可能会更有效fun
,但关键是要filter
编辑的列表不存在,它被融合了。
p
另一方面,如果没有重写规则,我们得到
Has.p1 :: [GHC.Integer.Type.Integer]
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, Cheap=False, Expandable=False,
Guidance=IF_ARGS [] 30 0}]
Has.p1 = GHC.Enum.enumDeltaInteger Has.p3 Has.p2
Has.p :: [GHC.Integer.Type.Integer]
[GblId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, Cheap=False, Expandable=False,
Guidance=IF_ARGS [] 30 0}]
Has.p = Has.filter @ GHC.Integer.Type.Integer Has.p4 Has.p1
[0 .. ]
列表( Has.p1
)的顶级 CAF ,并Has.filter
应用于(== 1000000000000)
列表。
所以这个确实创建了要过滤的实际列表 - 因此它的效率有点低。
但通常(运行已编译的二进制文件),这在内存消耗方面没有问题,因为列表在被消耗时会被垃圾收集。但是,由于我无法理解的原因,ghci[0 .. ]
在评估p
or时确实保留了列表s
(但它有自己的 副本[0 .. ]
,所以这里不是不需要的共享),正如可以从-hT
堆配置文件中收集到的那样(评估s
,所以只有一个列表单元格的可能来源。使用 ghci 调用+RTS -M300M -hT -RTS
,因此在内存使用量达到 300M 后不久,ghci 终止):
所以ghci中内存消耗的原因是要过滤的列表的硬编码。如果您使用Has.filter
提示符处提供的列表,则内存使用量与预期一样是恒定的。
我不确定 ghci 保留列表[0 .. ]
是错误还是预期行为。