haskell - Why would eta expansion degrade the performance of fib? -
i read this article says eta expansion
degrade performance of fib
, code below, fib1
faster other implementations. explains in slower versions, fib'
redefined every argument x. don't it. give more detailed explanation?
import system.environment import control.monad main = (mode:num:_) <- liftm (map read) getargs case mode of 1 -> print $ fib1 num 2 -> print $ fib2 num 3 -> print $ fib3 num 4 -> print $ fib4 num fib1 :: int->integer fib1 = (map fib' [0..] !!) fib' 0 = 1 fib' 1 = 1 fib' n = fib1 (n-1) + fib1 (n-2) fib2 :: int->integer fib2 x = map fib' [0..] !! x fib' 0 = 1 fib' 1 = 1 fib' n = fib2 (n-1) + fib2 (n-2) fib3 :: int->integer fib3 = (map fib' [0..] !!) fib' 0 = 1 fib' 1 = 1 fib' n = fib' (n-1) + fib' (n-2) fib4 :: int->integer fib4 x = map fib' [0..] !! x fib' 0 = 1 fib' 1 = 1 fib' n = fib' (n-1) + fib' (n-2)
i tested code above.
compiled ghc --make fib.hs
, fib1
faster others. compile ghc -o2 fib.hs
, fib1
, fib2
of same performance, while fib3
, fib4
slower.
it seems -o2
flag, fib2
further optimized, tested ghc --make fib.hs -ddump-simpl
see going on, , generated code 2 functions below
rec { fib1 [occ=loopbreaker] :: int -> integer [gblid, str=dmdtype] fib1 = !! @ integer (map @ int @ integer (\ (ds_d10b :: int) -> case ds_d10b of wild_x6 { ghc.types.i# ds1_d10c -> case ds1_d10c of _ [occ=dead] { __default -> + @ integer ghc.num.$fnuminteger (fib1 (- @ int ghc.num.$fnumint wild_x6 (ghc.types.i# 1))) (fib1 (- @ int ghc.num.$fnumint wild_x6 (ghc.types.i# 2))); 0 -> __integer 1; 1 -> __integer 1 } }) (enumfrom @ int ghc.enum.$fenumint (ghc.types.i# 0))) end rec } rec { fib2 [occ=loopbreaker] :: int -> integer [gblid, arity=1, str=dmdtype] fib2 = \ (x_ay6 :: int) -> !! @ integer (map @ int @ integer (\ (ds_d10x :: int) -> case ds_d10x of wild_x8 { ghc.types.i# ds1_d10y -> case ds1_d10y of _ [occ=dead] { __default -> + @ integer ghc.num.$fnuminteger (fib2 (- @ int ghc.num.$fnumint wild_x8 (ghc.types.i# 1))) (fib2 (- @ int ghc.num.$fnumint wild_x8 (ghc.types.i# 2))); 0 -> __integer 1; 1 -> __integer 1 } }) (enumfrom @ int ghc.enum.$fenumint (ghc.types.i# 0))) x_ay6 end rec }
after read code ghc -make -ddump-simpl fib.hs
generated, write 2 new function test it. compiled ghc --make fib.hs
, fib5
still faster fib6
, think these 2 functions make easier analyze.
fib5 :: int->integer fib5 = (!!) (map (\n-> case n of 0 -> 1 1 -> 1 _ -> fib5 (n-1) + fib5 (n-2)) [0..]) fib6 :: int->integer fib6 = \x-> (!!) (map (\n-> case n of 0 -> 1 1 -> 1 _ -> fib6 (n-1) + fib6 (n-2)) [0..]) x
looking @ linked article, seems it's difference between
fibs = let fibs' = ... in (\ x -> map fibs [0..] !! x)
verses
fibs = \ x -> let fibs' = ... in map fibs [0..] !! x
as can see, in first version fibs'
global constant never changes, , you're indexing that. in second version, fibs
function constructs "new", different fibs'
every value of x
. , that's performance difference.
Comments
Post a Comment