最初のバリアントには怠惰さが欠けていますが、それはあなたのせいではありません。パラメータ 6 を使用した実行のプロファイリング出力 ( +RTS -hd
) を比較すると、最初のヒントが得られます。

は最初のコードのプロファイリング出力ですが、

2 番目のコードの結果です。配列自体 ( ARR_WORDS
) は両方で同じスペースを取ります。:
また、最初のコードが (コンストラクターによって認識可能な)Int
コンストラクター (たまたま という名前)の大きなリストを生成することもわかりますInt#
。
Char
これは、(コンストラクターを使用して) s になるため、印刷された最終的な文字列にすることはできませんC#
。また、配列にはゼロが含まれており、ガベージ コレクターInt
には割り当ての代わりに (または実際にはコピーの)新しいコンストラクター。
:
また、コンストラクターに約 24MB、コンストラクターに約 16MBかかることにも注意してくださいI#
。前者には 3 単語、後者には 2 単語が必要であり、私のマシンでは 1 単語の長さが 8 バイトであることを知っていると、リストの長さは 100000=10^6 要素であることがわかります。したがって、非常に良い候補は、2 番目のインデックス パラメーターの範囲です。
では、この配列はどこにあるのでしょうか? への呼び出しを追跡しましょうshow
:
showsIArray :: (IArray a e, Ix i, Show i, Show e) => Int -> a i e -> ShowS
showsIArray p a =
showParen (p > 9) $
showString "array " .
shows (bounds a) .
showChar ' ' .
shows (assocs a)
( Data.Array.Baseからのコード)。明らかに、犯人はassocs
電話に出ているに違いないので、そのソースは次のとおりです。
assocs :: (IArray a e, Ix i) => a i e -> [(i, e)]
assocs arr = case bounds arr of
(l,u) -> [(i, arr ! i) | i <- range (l,u)]
インデックスのリストを探しているので、このrange
呼び出しは十分に疑わしく見えます。そのためには、GHC.Arrのソースを調べる必要があります(残念ながら haddock が台無しになっています)。
instance (Ix a, Ix b) => Ix (a, b) where
range ((l1,l2),(u1,u2)) = [ (i1,i2) | i1 <- range (l1,u1), i2 <- range (l2,u2) ]
そして今、犯人を見つけました: ここでrange (l2,u2)
は、リストに評価され[1..1000000]
、インデックスの最初のコンポーネントのすべてのステップで共有されます。
assocs
ここで、2 番目のコードの代わりに入れようとしてelems
、そこにスペース リークがあることを期待することに興味があると思います。しかし、あなたはそれを見ません。その理由は、インライン化されshow
ていないためですが、assocs
それ自体がインライン化され、range
共有を効果的に回避するなど、他の多くの関数もインライン化されます。-ddump-rule-firings
GHCに渡すことで (ある程度) 確認できます。
$ ghc --make -O2 -fspec-constr -ddump-rule-firings -fforce-recomp code2.hs -prof -fprof-auto
[1 of 1] Compiling Main ( code2.hs, code2.o )
Rule fired: SPEC GHC.Arr.$fIx(,)
Rule fired: unpack
Rule fired: Class op fail
Rule fired: unpack
Rule fired: Class op show
Rule fired: Class op newArray_
Rule fired: unsafeFreeze/STUArray
Rule fired: Class op >>=
Rule fired: Class op >>=
Rule fired: Class op showList
Rule fired: Class op rangeSize
Rule fired: Class op rangeSize
Rule fired: Class op bounds
Rule fired: Class op bounds
Rule fired: Class op numElements
Rule fired: Class op index
Rule fired: Class op unsafeAt
Rule fired: Class op range
Rule fired: fold/build
Rule fired: SPEC GHC.Real.^
Rule fired: unpack-list
Rule fired: foldr/app
Rule fired: unpack-append
Rule fired: foldr/app
Rule fired: unpack-append
Rule fired: >#
Rule fired: >#
Rule fired: x# <=# x#
Rule fired: x# -# x#
Rule fired: 0# *# x#
Rule fired: 0# +# x#
Linking code2 ...