A complete example
Here's a little example that shows the situation:
module A where
big :: () -> [Int]
big _ = [1..10^7]
Looks like a function, right? But what does GHC do? It floats the enum to the top level!
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
Ooops!
So what can we do?
Turn off optimizations
That works, -Onot
, but not desirable:
A.big :: () -> [Int]
[GblId, Arity=1]
A.big =
_ ->
enumFromTo
@ Int
$fEnumInt
(I# 1)
(^
@ Int
@ Type.Integer
$fNumInt
$fIntegralInteger
(I# 10)
(smallInteger 7))
Don't inline, and more functons
Make everything into a function, including the enumFromTo
, plumbing the parameter through to the workers:
big :: () -> [Int]
big u = myEnumFromTo u 1 (10^7)
{-# NOINLINE big #-}
myEnumFromTo :: () -> Int -> Int -> [Int]
myEnumFromTo _ n m = enumFromTo n m
{-# NOINLINE myEnumFromTo #-}
Now we are finally CAF-free! Even with -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
Yay.
What doesn't work?
Turn off -ffull-laziness
The full laziness transformation floats definitions outwards. It is on by default with -O1
or above. Let's try turning it off with -fno-full-laziness
. However, it doesn't work.