一个完整的例子
这里有一个小例子来说明这种情况:
module A where
big :: () -> [Int]
big _ = [1..10^7]
看起来像一个函数,对吧?但是 GHC 是做什么的呢?它将枚举浮动到顶层!
A.big1 :: [Int]
[ Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
ConLike=False, Cheap=False, Expandable=False,
Guidance=IF_ARGS [] 7 0}]
A.big1 =
case A.$wf1 10 A.big2 of ww_sDD { __DEFAULT ->
eftInt 1 ww_sDD
}
A.big :: () -> [Int]
[Arity=1,
Unf=Unf{Src=InlineStable, TopLvl=True, Arity=1, Value=True,
ConLike=True, Cheap=True, Expandable=True,
Guidance=ALWAYS_IF(unsat_ok=True,boring_ok=True)
Tmpl= \ _ -> A.big1}]
A.big = \ _ -> A.big1
哎呀!
那么我们能做些什么呢?
关闭优化
这可行,-Onot,但不可取:
A.big :: () -> [Int]
[GblId, Arity=1]
A.big =
\ _ ->
enumFromTo
@ Int
$fEnumInt
(I# 1)
(^
@ Int
@ Type.Integer
$fNumInt
$fIntegralInteger
(I# 10)
(smallInteger 7))
不要内联,还有更多函数
将一切变成一个函数,包括enumFromTo,将参数传递给工作人员:
big :: () -> [Int]
big u = myEnumFromTo u 1 (10^7)
{-# NOINLINE big #-}
myEnumFromTo :: () -> Int -> Int -> [Int]
myEnumFromTo _ n m = enumFromTo n m
{-# NOINLINE myEnumFromTo #-}
现在我们终于摆脱了 CAF!即使-O2
A.myEnumFromTo [InlPrag=NOINLINE]
:: () -> Int -> Int -> [Int]
A.myEnumFromTo =
\ _ (n_afx :: Int) (m_afy :: Int) ->
$fEnumInt_$cenumFromTo n_afx m_afy
A.big [InlPrag=NOINLINE] :: () -> [Int]
A.big = \ (u_abx :: ()) -> A.myEnumFromTo u_abx A.$s^2 lvl3_rEe
是的。
什么不起作用?
关闭 -ffull-laziness
完整的惰性转换将定义向外浮动。 -O1 或更高版本默认开启。让我们尝试使用-fno-full-laziness 将其关闭。但是,它不起作用。