7.6.1 のコアを見ると、作業を行う関数である-O2
andは、 orをインデックス タイプとして使用するかどうかにかかわらず、構造的に (ほぼ) 同じです。コアは長くて複雑なので、出力は次のようになります。-dsuppress-uniques
Main.main_$spoly_$wa
int
Int64
diff
$ diff Int_core.dump-simpl Int64_core.dump-simpl
11,12c11,12
< (Data.Array.Base.STUArray s GHC.Types.Int GHC.Types.Int)
< (Main.C (Data.Array.Base.STUArray s GHC.Types.Int GHC.Types.Int))
---
> (Data.Array.Base.STUArray s GHC.Int.Int64 GHC.Types.Int)
> (Main.C (Data.Array.Base.STUArray s GHC.Int.Int64 GHC.Types.Int))
26,27c26,27
< (Data.Array.Base.STUArray s GHC.Types.Int GHC.Types.Int)
< (Main.C (Data.Array.Base.STUArray s GHC.Types.Int GHC.Types.Int)))
---
> (Data.Array.Base.STUArray s GHC.Int.Int64 GHC.Types.Int)
> (Main.C (Data.Array.Base.STUArray s GHC.Int.Int64 GHC.Types.Int)))
さまざまなインデックスの種類、これらはもちろん異なります。
33,40d32
< l :: GHC.Types.Int
< [LclId]
< l = GHC.Types.I# sc } in
< let {
< u :: GHC.Types.Int
< [LclId]
< u = GHC.Types.I# sc1 } in
< let {
インデックス typeInt
の場合、GHC は、有効なインデックスの下限と上限を必要とするため、範囲外のインデックスに対していくらか有益なエラーを生成します。( のデフォルトの実装はindex
でオーバーライドされませんinstance Ix Int64
。)
45,46c37
< GHC.Types.False ->
< case poly_$w$j5 (GHC.Types.I# a) l u of wild2 { };
---
> GHC.Types.False -> case GHC.Arr.hopelessIndexError of wild1 { };
異なるエラー、indexError
対hopelessIndexError
。次の相違点もインデックス エラーのみに関係します。
49,50c40
< GHC.Types.False ->
< case poly_$w$j5 (GHC.Types.I# a) l u of wild2 { };
---
> GHC.Types.False -> case GHC.Arr.hopelessIndexError of wild2 { };
58c48
< case poly_$w$j4 y (GHC.Types.I# sc2) of wild3 { };
---
> case poly_$w$j3 y (GHC.Types.I# sc2) of wild4 { };
62c52
< case poly_$w$j4 y (GHC.Types.I# sc2) of wild5 { };
---
> case poly_$w$j3 y (GHC.Types.I# sc2) of wild5 { };
77,78c67
< GHC.Types.False ->
< case poly_$w$j3 (GHC.Types.I# a1) l u of wild6 { };
---
> GHC.Types.False -> case GHC.Arr.hopelessIndexError of wild6 { };
81,82c70
< GHC.Types.False ->
< case poly_$w$j3 (GHC.Types.I# a1) l u of wild7 { };
---
> GHC.Types.False -> case GHC.Arr.hopelessIndexError of wild7 { };
ここでもう一度、別のインデックス タイプ:
110c98
< GHC.Types.Int
---
> GHC.Int.Int64
152c140
< s GHC.Types.Int GHC.Types.Int>)>)
---
> s GHC.Int.Int64 GHC.Types.Int>)>)
そして最後に、0
さまざま1
なトップレベルの名前を取得しました。
177,178c165,166
< 0 -> (# sc5, lvl5 #);
< 1 -> (# sc5, lvl6 #)
---
> 0 -> (# sc5, lvl #);
> 1 -> (# sc5, lvl1 #)
したがって、実際の作業を行うコード全体は同じです。それでも、1つはスタックオーバーフローを引き起こします(ただ、-K9M
十分ですが、[-K8731K
ここでは十分です-K8730K
])が、もう1つはそうではありません。
この違いは、実際にはインデックス エラーによって引き起こされます。インデックス付きのコードは、コードが割り当てない再帰呼び出しごとにInt
2 つの boxedを割り当てます。Int
Int64
Main.main_$spoly_$wa [Occ=LoopBreaker]
:: forall s.
GHC.Prim.Int#
-> GHC.Prim.Int#
-> GHC.Prim.Int#
-> GHC.Prim.MutableByteArray# s
-> (GHC.Prim.~#)
*
(Data.Array.Base.STUArray s GHC.Types.Int GHC.Types.Int)
(Main.C (Data.Array.Base.STUArray s GHC.Types.Int GHC.Types.Int))
-> GHC.Prim.Int#
-> GHC.Prim.State# s
-> (# GHC.Prim.State# s, GHC.Types.Int #)
は、配列への2 つの参照を保持します。
これにより、より多くのスタックが使用され、これらのボックス化Int
された s をガベージ コレクションする必要があるため、GC の数値がはるかに大きくなります。また、インデックス エラーのサンクは、hopelessIndexError
サンクよりも少し大きくなります。
さて、コンパイラを助けるなら
- newtype ラッパーの削除
- 配列内で関数を正格にする (バング パターンまたはで
data C a = C !a
)
または他の方法で、ワーカー内の配列への参照が1 つしかないため、指定された引数のスタック オーバーフローなしで管理するより優れたコードを生成します。したがってInt
、境界に対するボックス化された s の割り当ては必要ありません。
このアルゴリズムは、コンパイラの助けを借りても、わずかに大きな引数に対してスタック オーバーフローを引き起こすことに注意してください。