はい、ポリモーフィック型シグネチャは、各段階で再計算されていることを意味します。ghc-7.4.2 によって生成されたコア-O2
:
lvl_rcZ :: GHC.Integer.Type.Integer
[GblId, Str=DmdType]
lvl_rcZ = __integer 1
Rec {
PolyFib.fib [Occ=LoopBreaker]
:: forall a_a9W. GHC.Num.Num a_a9W => [a_a9W]
[GblId, Arity=1, Str=DmdType L]
PolyFib.fib =
\ (@ a_aal) ($dNum_aam :: GHC.Num.Num a_aal) ->
GHC.Types.:
@ a_aal
(GHC.Num.fromInteger @ a_aal $dNum_aam lvl_rcZ)
(GHC.Types.:
@ a_aal
(GHC.Num.fromInteger @ a_aal $dNum_aam lvl_rcZ)
(GHC.List.zipWith
@ a_aal
@ a_aal
@ a_aal
(GHC.Num.+ @ a_aal $dNum_aam)
(PolyFib.fib @ a_aal $dNum_aam)
(case PolyFib.fib @ a_aal $dNum_aam of _ {
[] -> GHC.List.tail1 @ a_aal;
: _ xs_abD -> xs_abD
})))
end Rec }
その理由は、 に属する各型のフィボナッチ数のリストをキャッシュするのは現実的Num
でfib
はなく、明示的にポリモーフィックな値であるため、まったくキャッシュされないためです。
少なくとも各タイプの計算のためにキャッシュしたい場合は、ローカルリストを使用してください
pfibs :: Num a => [a]
pfibs = res
where
res = 1 : 1 : zipWith (+) res (tail res)
pfibs !! 500
リストは各計算で単相的であるため、計算ごとにキャッシングを行います(したがって、高速です)。クエリごとに再計算されますが (単形名にバインドしない限り)、単一のリスト要素ごとには再計算されません。
*PolyFib> pfibs !! 999999 :: Int
-4249520595888827205
(0.31 secs, 137462088 bytes)