Haskellのnewtypeの魔法



Haskellで新しいデータ型を定義する主な方法は、データ構造を使用することです。 ただし、 newtype



もあります。 Haskellプラクティショナーは絶えずnewtype



コンストラクトを使用します;人気のあるlint linterは、可能であればdata



newtype



に置き換えるdata



を提案します。







しかし、なぜですか?









最初はこの記事を初心者向けに計画しました。 実際、 newtype



コンストラクトはHaskellチュートリアルの最初の章で言及されています。 これは単純なアイデアのようです:データ型の表現を制限し、実行速度を向上させます。 さまざまなソースで、 newtype



がポインターのネストを保存する参照を見つけることができます。 しかし、コンパイラでこの構造が実際に何が起こるのか、なぜそれがとてもクールで必要なのかについての詳細な分析は見つかりませんでした。 これらのギャップを埋めるために、Habrに関する記事を書くことにしました。







そのため、 haskellスタックとHaskellおよびGHCランタイムモデルの基本的な知識が必要です(遅延計算とは何か、サンク(計算されていないオブジェクト)、GHCスタックとヒープについて少し聞いたことがあります)。







意味論



newtype



コンストラクトの構文は、データコンストラクトとまったく同じです。ただし、 newtype



は、コンストラクターとボックス化された型フィールドを1つだけnewtype



ことができます。







 -- |         data MyValDL = MyValDLC Int -- |   ,       thunk' -- (   Int) data MyValDS = MyValDSC !Int -- |            , --     newtype newtype MyValN = MyValNC Int
      
      





ところで、あらゆる種類のレコード構文とファントムタイプも機能します。







 newtype MyFunnyA abc = MyFunnyA { getA :: a }
      
      





しかし、 MyValDL



MyValDS



)とMyValN



違いは何ですか?







Haskell'98レポートは、 newtype



コンストラクトが、既存の表現と同一の表現を持つ新しい型を導入すると述べています。 つまり、 Int



MyValN



同型です。 しかし、これはdata



型ではそうではありませんか? わかった、いや。 問題の事実は、Haskellには持ち上がったタイプと持ち上がっていないタイプがあるということです。 追加のボトム要素(ボトム、またはtypes)は、 data



を使用して宣言されたすべてのタイプに追加されdata



-それらは浮き上がりdata



(プログラムの場合、ボトムはundefined



)。 つまり、「 MyValDLC ⊥ :: MyValDL



」と「 ⊥ :: MyValDL



」は異なる値です。 data



とは異なり、 newtype



型は発生しません(unlifted型)。つまり、 ⊥ :: MyValN



入れ子になった型から "借入"されます( MyValN ⊥



viaを介して)。







コンパイラーにとって、隆起した型とは、ポインターの余分なレイヤーを意味すると言うことができます(ポインターはネストされたオブジェクト、または下(未定義)を参照できます)。 プログラマーにとって、これは、コンストラクターのdata



フィールドにundefined



が含まれる場合、すべてが失われるわけではないことを意味します。このフィールドに触れるまで、プログラムは中断しません。 一方、未計算フィールドはメモリリーク(一連のサンク)である可能性があります。 MyValDS



はもう少し複雑ですMyValDS



はすぐにMyValDSC ⊥



に計算されるようですが、これら2つのコンストラクターのセマンティクスは同じです。 ちなみに、専門家は、データコンストラクターですべてのフィールドを厳密に宣言することをお勧めします。ただし、フィールドを遅延的に使用する必要が実際にある場合を除きます。







Haskell wikiには、データとnewtype



違いを示す素晴らしい例があります。 ここでそれらを提供し、無料の翻訳と私のタイプ名に合わせて調整します:







 --    (  ), --     xDL :: Int xDL = case MyValDLC undefined of MyValDLC _ -> 1 -- 1 --   ,  undefined   xDS :: Int xDS = case MyValDSC undefined of MyValDSC _ -> 1 -- undefined -- newtype    Int,    1 -- (  ,  ,  .  yInt) xN :: Int xN = case MyValNC undefined of MyValNC _ -> 1 -- 1 --     yDL :: Int yDL = case undefined of MyValDLC _ -> 1 -- undefined --     yDS :: Int yDS = case undefined of MyValDSC _ -> 1 -- undefined -- newtype    Int,   MyValN --        ! yN :: Int yN = case undefined of MyValNC _ -> 1 -- 1 --      Int: -- case     undefined, --     , --        yInt :: Int yInt = case (undefined :: Int) of _ -> 1 -- 1
      
      





上記の説明は、 Haskell wikiの私の解釈です。 しかし、私たちはここで止まらず、さらにいくつかの質問を検討します。







どのように機能しますか?



コンパイラーに元の型とそのnewtype



ラッパーの同じ表現を要求するということは、次のことを意味します。









GHCは、「目に見える」Haskell型システムと代表型の2つのレベルで型を処理します。 目に見える型システムは、Haskellでプログラミングするときに使用するものです。 ただし、ある時点で、コンパイラはHaskell型をマシンビューに変換します。 多くの場合、Haskellの2つの異なる型がマシンコードで同じ表現を持つことがあります。 今日のGHCでは、ロールシステムを使用して型を名目上だけでなく、その表現に従って比較することができます。 これにより、 Data.Type.CoercionおよびData.Coerceモジュールに自由な型変換のメカニズム(Has​​kell型システムのレベルでのみ表示可能)を実装できました。







上記を考慮すると、 newtype



を実装する一般的な考え方は明らかですnewtype



すべてのパックされた値は、コンストラクター(オブジェクト情報テーブル)へのポインターを持つ説明の形式で提示されます。 したがって、 newtype



型の値は、その説明でネストされた値のコンストラクターへのポインターを直接使用できます。 type



同義語のようなものが、より低いレベルでのみ判明します。













すべてのHaskellプログラマーは、GHCがソースコードを直接アセンブラーにコンパイルするのではなく、いくつかの段階で複雑な一連のコード変換を実行し、そのほとんどすべてを最適化することを知っています。 最初に、Haskell構文ツリーは、言語の簡易バージョンであるGHCコア(Fシステムに基づいています)に変換されます。 次に、Coreは機能的なSTG(Spineless Tagless G-machine)に変換され、次に命令型C--(例外処理とガベージコレクターをサポートする特別な中間言語)に変換され、そこからさまざまな方法でアセンブラーに変換されます。







newtype



型のコンストラクタが実行時に「消える」というステートメントのようです。 しかし、これがどのように起こるかを理解することは非常に難しいことが判明しました。 GHC WebサイトでのSTGの説明は、STGが代表的なタイプでのみ動作すること、つまり、 newtype



はその前に失われなければならないことを明確にしています。 別のGHC wikiページでは 、一部の型は常に表示され、一部は型チェッカー専用です(後者は、生成コードのさまざまなレベルでtcプレフィックスを持っているようです)。 newtype



型で何が起こるかを確認するために、次の例を使用して、コンパイルされたコードのすべての中間段階を調べることにしました。







 newtype MyNewtypeStruct = MyNewtypeConstr { unNewtypeStruct :: Int } data MyDataStruct = MyDataConstr { unDataStruct :: Int } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD x = case x of MyNewtypeConstr y -> MyDataConstr y dToNt :: MyDataStruct -> MyNewtypeStruct dToNt x = case x of MyDataConstr y -> MyNewtypeConstr y
      
      





結果は、最初の段階ですぐに現れました。







 stack exec ghc-core -- --no-asm Main.hs -fforce-recomp -O0 -fno-enable-rewrite-rules
      
      





同じ名前のhackageパッケージで利用可能なghc-core



プログラムは、少しクリーンアップされたGHCコアを表示します。 すでにこの段階で、 MyNewtypeConstr



すべての出現はcast



操作に置き換えcast



ますが、 MyDataConstr



正直にそのまま残ります。







 unNewtypeStruct1_rG2 :: MyNewtypeStruct -> MyNewtypeStruct unNewtypeStruct1_rG2 = \ (ds_dGl :: MyNewtypeStruct) -> ds_dGl unNewtypeStruct :: MyNewtypeStruct -> Int unNewtypeStruct = unNewtypeStruct1_rG2 `cast` (<MyNewtypeStruct>_R -> N:MyNewtypeStruct[0] :: ((MyNewtypeStruct -> MyNewtypeStruct) :: *) ~R# ((MyNewtypeStruct -> Int) :: *)) unDataStruct :: MyDataStruct -> Int unDataStruct = \ (ds_dGj :: MyDataStruct) -> case ds_dGj of _ [Occ=Dead] { MyDataConstr ds1_dGk -> ds1_dGk } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD = MyDataConstr `cast` (Sym N:MyNewtypeStruct[0] -> <MyDataStruct>_R :: ((Int -> MyDataStruct) :: *) ~R# ((MyNewtypeStruct -> MyDataStruct) :: *)) dToNt :: MyDataStruct -> MyNewtypeStruct dToNt = \ (x_awb :: MyDataStruct) -> case x_awb of _ [Occ=Dead] { MyDataConstr y_awc -> y_awc `cast` (Sym N:MyNewtypeStruct[0] :: (Int :: *) ~R# (MyNewtypeStruct :: *))
      
      





次のステージはSTGであり、次のコマンドで表示できます。







 stack exec ghc -- Main.hs -fforce-recomp -O0 -fno-enable-rewrite-rules -ddump-stg > Main.stg
      
      





興味深い詳細を除いて、Coreとそれほど大きな違いはありませんMain.MyDataConstr



は生成されたコードで明示的に定義され、 Main.MyNewtypeConstr



です。







 Main.MyDataConstr :: GHC.Types.Int -> Main.MyDataStruct [GblId[DataCon], Arity=1, Caf=NoCafRefs, Str=DmdType <L,U>m, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1];
      
      





レベルMain.$tc'MyNewtypeConstr



以降では、 Main.$tc'MyNewtypeConstr



Main.$tc'MyDataConstr



構造が見つかりますが、 Main.MyDataConstr



newtype



ペアを見つけません。 どうやら、 $tc



(タイプチェッカーという言葉から)は、タイプチェックのレベルでのみ使用されるタイプの別のヒントです。







ご覧のとおり、すでにGHCコア変換の段階で、 newtype



コンストラクターはプリミティブ型変換に置き換えられています。 Main.unNewtypeStruct_entry()



レベルでは、低レベルの命令コードMain.unNewtypeStruct_entry()



Main.unDataStruct_entry()



unNewtypeStruct



して、 unNewtypeStruct



は異なり、 unNewtypeStruct



が事実上何もしないことを確認unDataStruct



ます。

すべての出力レベルは、いくつかのコマンドで表示できます。







 stack exec ghc -- ${filename}.hs -fforce-recomp -O0 -fno-enable-rewrite-rules -fllvm -keep-llvm-files stack exec ghc-core -- --no-asm --no-syntax ${filename}.hs -fforce-recomp -O0 -fno-enable-rewrite-rules > ${filename}.hcr stack exec ghc -- ${filename}.hs -fforce-recomp -O0 -fno-enable-rewrite-rules -ddump-stg > ${filename}.stg stack exec ghc -- ${filename}.hs -fforce-recomp -O0 -fno-enable-rewrite-rules -ddump-opt-cmm > ${filename}.cmm
      
      





私がフォーマットした出力は猫の下にあります。 多かれ少なかれ興味深い部分だけを残しました(テキストが多すぎます)。







GHCフェーズアウト
 -- CORE ------------------------------------------------------------------------ unNewtypeStruct1_rG2 :: MyNewtypeStruct -> MyNewtypeStruct unNewtypeStruct1_rG2 = \ (ds_dGl :: MyNewtypeStruct) -> ds_dGl unNewtypeStruct :: MyNewtypeStruct -> Int unNewtypeStruct = unNewtypeStruct1_rG2 `cast` (<MyNewtypeStruct>_R -> N:MyNewtypeStruct[0] :: ((MyNewtypeStruct -> MyNewtypeStruct) :: *) ~R# ((MyNewtypeStruct -> Int) :: *)) unDataStruct :: MyDataStruct -> Int unDataStruct = \ (ds_dGj :: MyDataStruct) -> case ds_dGj of _ [Occ=Dead] { MyDataConstr ds1_dGk -> ds1_dGk } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD = MyDataConstr `cast` (Sym N:MyNewtypeStruct[0] -> <MyDataStruct>_R :: ((Int -> MyDataStruct) :: *) ~R# ((MyNewtypeStruct -> MyDataStruct) :: *)) dToNt :: MyDataStruct -> MyNewtypeStruct dToNt = \ (x_awb :: MyDataStruct) -> case x_awb of _ [Occ=Dead] { MyDataConstr y_awc -> y_awc `cast` (Sym N:MyNewtypeStruct[0] :: (Int :: *) ~R# (MyNewtypeStruct :: *)) -- ... $tc'MyNewtypeConstr1_rGD :: TrName $tc'MyNewtypeConstr1_rGD = TrNameS "'MyNewtypeConstr"# $tc'MyDataConstr1_rGF :: TrName $tc'MyDataConstr1_rGF = TrNameS "'MyDataConstr"# -- .. $tcMyNewtypeStruct1_rGE :: TrName $tcMyNewtypeStruct1_rGE = TrNameS "MyNewtypeStruct"# $tcMyDataStruct1_rGG :: TrName $tcMyDataStruct1_rGG = TrNameS "MyDataStruct"# -- ... -- STG ------------------------------------------------------------------------- unNewtypeStruct1_rG2 :: Main.MyNewtypeStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = sat-only \r srt:SRT:[] [ds_sQ7] ds_sQ7; Main.unNewtypeStruct :: Main.MyNewtypeStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] unNewtypeStruct1_rG2 eta_B1; Main.unDataStruct :: Main.MyDataStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [ds_sQ8] case ds_sQ8 of _ [Occ=Dead] { Main.MyDataConstr ds1_sQa [Occ=Once] -> ds1_sQa; }; Main.ntToD :: Main.MyNewtypeStruct -> Main.MyDataStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; Main.dToNt :: Main.MyDataStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [x_sQb] case x_sQb of _ [Occ=Dead] { Main.MyDataConstr y_sQd [Occ=Once] -> y_sQd; }; -- ... constructors seem to be defined exactly the same way for both types ... -- There is one more definition in the STG dump Main.MyDataConstr :: GHC.Types.Int -> Main.MyDataStruct [GblId[DataCon], Arity=1, Caf=NoCafRefs, Str=DmdType <L,U>m, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; -- C-- ------------------------------------------------------------------------- unNewtypeStruct1_rG2_entry() // [R2] { [(cQj, unNewtypeStruct1_rG2_info: const 4294967301; const 0; const 15;)] } {offset cQj: _sQ8::P64 = R2; goto cQl; cQl: R1 = _sQ8::P64 & (-8); call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } Main.unNewtypeStruct_entry() // [R2] { [(cQv, Main.unNewtypeStruct_info: const 4294967301; const 0; const 15;)] } {offset cQv: _B1::P64 = R2; goto cQx; cQx: R2 = _B1::P64; call unNewtypeStruct1_rG2_info(R2) args: 8, res: 0, upd: 8; } } Main.unDataStruct_entry() // [R2] { [(cQJ, block_cQJ_info: const 0; const 32;), (cQM, Main.unDataStruct_info: const 4294967301; const 0; const 15;)] } {offset cQM: _sQ9::P64 = R2; if ((Sp + -8) < SpLim) goto cQN; else goto cQO; cQN: R2 = _sQ9::P64; R1 = Main.unDataStruct_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cQO: I64[Sp - 8] = block_cQJ_info; R1 = _sQ9::P64; Sp = Sp - 8; if (R1 & 7 != 0) goto cQJ; else goto cQK; cQK: call (I64[R1])(R1) returns to cQJ, args: 8, res: 8, upd: 8; cQJ: _sQa::P64 = R1; _sQb::P64 = P64[_sQa::P64 + 7]; R1 = _sQb::P64 & (-8); Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } section ""data" . $tc'MyNewtypeConstr1_rGD_closure" { $tc'MyNewtypeConstr1_rGD_closure: const GHC.Types.TrNameS_static_info; const cRI_str; } section ""data" . Main.$tc'MyNewtypeConstr_closure" { Main.$tc'MyNewtypeConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyNewtypeConstr1_rGD_closure+1; const 10344856529254187725; const 4384341159368653246; const 3; } section ""data" . $tc'MyDataConstr1_rGF_closure" { $tc'MyDataConstr1_rGF_closure: const GHC.Types.TrNameS_static_info; const cRU_str; } section ""data" . Main.$tc'MyDataConstr_closure" { Main.$tc'MyDataConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyDataConstr1_rGF_closure+1; const 12971553621823397951; const 6686958652479025466; const 3; } section ""data" . Main.MyDataConstr_closure" { Main.MyDataConstr_closure: const Main.MyDataConstr_info; } Main.MyDataConstr_entry() // [R2] { [(cSE, Main.MyDataConstr_info: const 4294967301; const 0; const 15;)] } {offset cSE: _B1::P64 = R2; goto cSG; cSG: Hp = Hp + 16; if (Hp > I64[BaseReg + 856]) goto cSI; else goto cSH; cSI: I64[BaseReg + 904] = 16; goto cSF; cSF: R2 = _B1::P64; R1 = Main.MyDataConstr_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cSH: I64[Hp - 8] = Main.MyDataConstr_con_info; P64[Hp] = _B1::P64; _cSD::P64 = Hp - 7; R1 = _cSD::P64; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_con_entry() // [] { [(cSN, Main.MyDataConstr_con_info: const iSP_str-Main.MyDataConstr_con_info; const 1; const 2;)] } {offset cSN: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_static_entry() // [] { [(cSO, Main.MyDataConstr_static_info: const iSQ_str-Main.MyDataConstr_static_info; const 1; const 7;)] } {offset cSO: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } -- LLVM ------------------------------------------------------------------------ %Main_zdtczqMyNewtypeConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyNewtypeConstr_closure$def = internal global %Main_zdtczqMyNewtypeConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGD_closure_struct* @rGD_closure$def to i64),i64 1), i64 -8101887544455363891, i64 4384341159368653246, i64 3}> @Main_zdtczqMyNewtypeConstr_closure = alias i8* bitcast (%Main_zdtczqMyNewtypeConstr_closure_struct* @Main_zdtczqMyNewtypeConstr_closure$def to i8*) %Main_zdtcMyNewtypeStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyNewtypeStruct_closure$def = internal global %Main_zdtcMyNewtypeStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGE_closure_struct* @rGE_closure$def to i64),i64 1), i64 2735651172251469986, i64 2399541496478989519, i64 3}> @Main_zdtcMyNewtypeStruct_closure = alias i8* bitcast (%Main_zdtcMyNewtypeStruct_closure_struct* @Main_zdtcMyNewtypeStruct_closure$def to i8*) %Main_zdtczqMyDataConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyDataConstr_closure$def = internal global %Main_zdtczqMyDataConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGF_closure_struct* @rGF_closure$def to i64),i64 1), i64 -5475190451886153665, i64 6686958652479025466, i64 3}> @Main_zdtczqMyDataConstr_closure = alias i8* bitcast (%Main_zdtczqMyDataConstr_closure_struct* @Main_zdtczqMyDataConstr_closure$def to i8*) %Main_zdtcMyDataStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyDataStruct_closure$def = internal global %Main_zdtcMyDataStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGG_closure_struct* @rGG_closure$def to i64),i64 1), i64 5826051442705447975, i64 -4331072423017222539, i64 3}> @Main_zdtcMyDataStruct_closure = alias i8* bitcast (%Main_zdtcMyDataStruct_closure_struct* @Main_zdtcMyDataStruct_closure$def to i8*) %Main_MyDataConstr_closure_struct = type <{i64}> @Main_MyDataConstr_closure$def = internal global %Main_MyDataConstr_closure_struct<{i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i64)}> @Main_MyDataConstr_closure = alias i8* bitcast (%Main_MyDataConstr_closure_struct* @Main_MyDataConstr_closure$def to i8*) @Main_MyDataConstr_info = internal alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i8*) define internal ghccc void @Main_MyDataConstr_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 4294967301, i64 0, i64 15}> { cW0: ... ret void } @Main_MyDataConstr_con_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i8*) define ghccc void @Main_MyDataConstr_con_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWK_str_struct* @iWK_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i64)),i64 0), i64 1, i64 2}> { ... } @Main_MyDataConstr_static_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i8*) define ghccc void @Main_MyDataConstr_static_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWL_str_struct* @iWL_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i64)),i64 0), i64 1, i64 7}> { ... }
      
      



Main_zdtczqMyNewtypeConstr_closure_struct <{I64 ptrtoint(I64にI8 * @ghczmprim_GHCziTypes_TyCon_static_info)は、追加I64()I64 ptrtoint(%のMain_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ DEF I64に、I64 -- CORE ------------------------------------------------------------------------ unNewtypeStruct1_rG2 :: MyNewtypeStruct -> MyNewtypeStruct unNewtypeStruct1_rG2 = \ (ds_dGl :: MyNewtypeStruct) -> ds_dGl unNewtypeStruct :: MyNewtypeStruct -> Int unNewtypeStruct = unNewtypeStruct1_rG2 `cast` (<MyNewtypeStruct>_R -> N:MyNewtypeStruct[0] :: ((MyNewtypeStruct -> MyNewtypeStruct) :: *) ~R# ((MyNewtypeStruct -> Int) :: *)) unDataStruct :: MyDataStruct -> Int unDataStruct = \ (ds_dGj :: MyDataStruct) -> case ds_dGj of _ [Occ=Dead] { MyDataConstr ds1_dGk -> ds1_dGk } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD = MyDataConstr `cast` (Sym N:MyNewtypeStruct[0] -> <MyDataStruct>_R :: ((Int -> MyDataStruct) :: *) ~R# ((MyNewtypeStruct -> MyDataStruct) :: *)) dToNt :: MyDataStruct -> MyNewtypeStruct dToNt = \ (x_awb :: MyDataStruct) -> case x_awb of _ [Occ=Dead] { MyDataConstr y_awc -> y_awc `cast` (Sym N:MyNewtypeStruct[0] :: (Int :: *) ~R# (MyNewtypeStruct :: *)) -- ... $tc'MyNewtypeConstr1_rGD :: TrName $tc'MyNewtypeConstr1_rGD = TrNameS "'MyNewtypeConstr"# $tc'MyDataConstr1_rGF :: TrName $tc'MyDataConstr1_rGF = TrNameS "'MyDataConstr"# -- .. $tcMyNewtypeStruct1_rGE :: TrName $tcMyNewtypeStruct1_rGE = TrNameS "MyNewtypeStruct"# $tcMyDataStruct1_rGG :: TrName $tcMyDataStruct1_rGG = TrNameS "MyDataStruct"# -- ... -- STG ------------------------------------------------------------------------- unNewtypeStruct1_rG2 :: Main.MyNewtypeStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = sat-only \r srt:SRT:[] [ds_sQ7] ds_sQ7; Main.unNewtypeStruct :: Main.MyNewtypeStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] unNewtypeStruct1_rG2 eta_B1; Main.unDataStruct :: Main.MyDataStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [ds_sQ8] case ds_sQ8 of _ [Occ=Dead] { Main.MyDataConstr ds1_sQa [Occ=Once] -> ds1_sQa; }; Main.ntToD :: Main.MyNewtypeStruct -> Main.MyDataStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; Main.dToNt :: Main.MyDataStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [x_sQb] case x_sQb of _ [Occ=Dead] { Main.MyDataConstr y_sQd [Occ=Once] -> y_sQd; }; -- ... constructors seem to be defined exactly the same way for both types ... -- There is one more definition in the STG dump Main.MyDataConstr :: GHC.Types.Int -> Main.MyDataStruct [GblId[DataCon], Arity=1, Caf=NoCafRefs, Str=DmdType <L,U>m, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; -- C-- ------------------------------------------------------------------------- unNewtypeStruct1_rG2_entry() // [R2] { [(cQj, unNewtypeStruct1_rG2_info: const 4294967301; const 0; const 15;)] } {offset cQj: _sQ8::P64 = R2; goto cQl; cQl: R1 = _sQ8::P64 & (-8); call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } Main.unNewtypeStruct_entry() // [R2] { [(cQv, Main.unNewtypeStruct_info: const 4294967301; const 0; const 15;)] } {offset cQv: _B1::P64 = R2; goto cQx; cQx: R2 = _B1::P64; call unNewtypeStruct1_rG2_info(R2) args: 8, res: 0, upd: 8; } } Main.unDataStruct_entry() // [R2] { [(cQJ, block_cQJ_info: const 0; const 32;), (cQM, Main.unDataStruct_info: const 4294967301; const 0; const 15;)] } {offset cQM: _sQ9::P64 = R2; if ((Sp + -8) < SpLim) goto cQN; else goto cQO; cQN: R2 = _sQ9::P64; R1 = Main.unDataStruct_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cQO: I64[Sp - 8] = block_cQJ_info; R1 = _sQ9::P64; Sp = Sp - 8; if (R1 & 7 != 0) goto cQJ; else goto cQK; cQK: call (I64[R1])(R1) returns to cQJ, args: 8, res: 8, upd: 8; cQJ: _sQa::P64 = R1; _sQb::P64 = P64[_sQa::P64 + 7]; R1 = _sQb::P64 & (-8); Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } section ""data" . $tc'MyNewtypeConstr1_rGD_closure" { $tc'MyNewtypeConstr1_rGD_closure: const GHC.Types.TrNameS_static_info; const cRI_str; } section ""data" . Main.$tc'MyNewtypeConstr_closure" { Main.$tc'MyNewtypeConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyNewtypeConstr1_rGD_closure+1; const 10344856529254187725; const 4384341159368653246; const 3; } section ""data" . $tc'MyDataConstr1_rGF_closure" { $tc'MyDataConstr1_rGF_closure: const GHC.Types.TrNameS_static_info; const cRU_str; } section ""data" . Main.$tc'MyDataConstr_closure" { Main.$tc'MyDataConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyDataConstr1_rGF_closure+1; const 12971553621823397951; const 6686958652479025466; const 3; } section ""data" . Main.MyDataConstr_closure" { Main.MyDataConstr_closure: const Main.MyDataConstr_info; } Main.MyDataConstr_entry() // [R2] { [(cSE, Main.MyDataConstr_info: const 4294967301; const 0; const 15;)] } {offset cSE: _B1::P64 = R2; goto cSG; cSG: Hp = Hp + 16; if (Hp > I64[BaseReg + 856]) goto cSI; else goto cSH; cSI: I64[BaseReg + 904] = 16; goto cSF; cSF: R2 = _B1::P64; R1 = Main.MyDataConstr_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cSH: I64[Hp - 8] = Main.MyDataConstr_con_info; P64[Hp] = _B1::P64; _cSD::P64 = Hp - 7; R1 = _cSD::P64; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_con_entry() // [] { [(cSN, Main.MyDataConstr_con_info: const iSP_str-Main.MyDataConstr_con_info; const 1; const 2;)] } {offset cSN: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_static_entry() // [] { [(cSO, Main.MyDataConstr_static_info: const iSQ_str-Main.MyDataConstr_static_info; const 1; const 7;)] } {offset cSO: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } -- LLVM ------------------------------------------------------------------------ %Main_zdtczqMyNewtypeConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyNewtypeConstr_closure$def = internal global %Main_zdtczqMyNewtypeConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGD_closure_struct* @rGD_closure$def to i64),i64 1), i64 -8101887544455363891, i64 4384341159368653246, i64 3}> @Main_zdtczqMyNewtypeConstr_closure = alias i8* bitcast (%Main_zdtczqMyNewtypeConstr_closure_struct* @Main_zdtczqMyNewtypeConstr_closure$def to i8*) %Main_zdtcMyNewtypeStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyNewtypeStruct_closure$def = internal global %Main_zdtcMyNewtypeStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGE_closure_struct* @rGE_closure$def to i64),i64 1), i64 2735651172251469986, i64 2399541496478989519, i64 3}> @Main_zdtcMyNewtypeStruct_closure = alias i8* bitcast (%Main_zdtcMyNewtypeStruct_closure_struct* @Main_zdtcMyNewtypeStruct_closure$def to i8*) %Main_zdtczqMyDataConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyDataConstr_closure$def = internal global %Main_zdtczqMyDataConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGF_closure_struct* @rGF_closure$def to i64),i64 1), i64 -5475190451886153665, i64 6686958652479025466, i64 3}> @Main_zdtczqMyDataConstr_closure = alias i8* bitcast (%Main_zdtczqMyDataConstr_closure_struct* @Main_zdtczqMyDataConstr_closure$def to i8*) %Main_zdtcMyDataStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyDataStruct_closure$def = internal global %Main_zdtcMyDataStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGG_closure_struct* @rGG_closure$def to i64),i64 1), i64 5826051442705447975, i64 -4331072423017222539, i64 3}> @Main_zdtcMyDataStruct_closure = alias i8* bitcast (%Main_zdtcMyDataStruct_closure_struct* @Main_zdtcMyDataStruct_closure$def to i8*) %Main_MyDataConstr_closure_struct = type <{i64}> @Main_MyDataConstr_closure$def = internal global %Main_MyDataConstr_closure_struct<{i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i64)}> @Main_MyDataConstr_closure = alias i8* bitcast (%Main_MyDataConstr_closure_struct* @Main_MyDataConstr_closure$def to i8*) @Main_MyDataConstr_info = internal alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i8*) define internal ghccc void @Main_MyDataConstr_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 4294967301, i64 0, i64 15}> { cW0: ... ret void } @Main_MyDataConstr_con_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i8*) define ghccc void @Main_MyDataConstr_con_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWK_str_struct* @iWK_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i64)),i64 0), i64 1, i64 2}> { ... } @Main_MyDataConstr_static_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i8*) define ghccc void @Main_MyDataConstr_static_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWL_str_struct* @iWL_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i64)),i64 0), i64 1, i64 7}> { ... }



Main_zdtcMyNewtypeStruct_closure_struct <{I64 ptrtoint(I64にI8 * @ghczmprim_GHCziTypes_TyCon_static_info)は、追加I64()I64 ptrtoint(%のMain_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ DEF I64に、I64 -- CORE ------------------------------------------------------------------------ unNewtypeStruct1_rG2 :: MyNewtypeStruct -> MyNewtypeStruct unNewtypeStruct1_rG2 = \ (ds_dGl :: MyNewtypeStruct) -> ds_dGl unNewtypeStruct :: MyNewtypeStruct -> Int unNewtypeStruct = unNewtypeStruct1_rG2 `cast` (<MyNewtypeStruct>_R -> N:MyNewtypeStruct[0] :: ((MyNewtypeStruct -> MyNewtypeStruct) :: *) ~R# ((MyNewtypeStruct -> Int) :: *)) unDataStruct :: MyDataStruct -> Int unDataStruct = \ (ds_dGj :: MyDataStruct) -> case ds_dGj of _ [Occ=Dead] { MyDataConstr ds1_dGk -> ds1_dGk } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD = MyDataConstr `cast` (Sym N:MyNewtypeStruct[0] -> <MyDataStruct>_R :: ((Int -> MyDataStruct) :: *) ~R# ((MyNewtypeStruct -> MyDataStruct) :: *)) dToNt :: MyDataStruct -> MyNewtypeStruct dToNt = \ (x_awb :: MyDataStruct) -> case x_awb of _ [Occ=Dead] { MyDataConstr y_awc -> y_awc `cast` (Sym N:MyNewtypeStruct[0] :: (Int :: *) ~R# (MyNewtypeStruct :: *)) -- ... $tc'MyNewtypeConstr1_rGD :: TrName $tc'MyNewtypeConstr1_rGD = TrNameS "'MyNewtypeConstr"# $tc'MyDataConstr1_rGF :: TrName $tc'MyDataConstr1_rGF = TrNameS "'MyDataConstr"# -- .. $tcMyNewtypeStruct1_rGE :: TrName $tcMyNewtypeStruct1_rGE = TrNameS "MyNewtypeStruct"# $tcMyDataStruct1_rGG :: TrName $tcMyDataStruct1_rGG = TrNameS "MyDataStruct"# -- ... -- STG ------------------------------------------------------------------------- unNewtypeStruct1_rG2 :: Main.MyNewtypeStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = sat-only \r srt:SRT:[] [ds_sQ7] ds_sQ7; Main.unNewtypeStruct :: Main.MyNewtypeStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] unNewtypeStruct1_rG2 eta_B1; Main.unDataStruct :: Main.MyDataStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [ds_sQ8] case ds_sQ8 of _ [Occ=Dead] { Main.MyDataConstr ds1_sQa [Occ=Once] -> ds1_sQa; }; Main.ntToD :: Main.MyNewtypeStruct -> Main.MyDataStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; Main.dToNt :: Main.MyDataStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [x_sQb] case x_sQb of _ [Occ=Dead] { Main.MyDataConstr y_sQd [Occ=Once] -> y_sQd; }; -- ... constructors seem to be defined exactly the same way for both types ... -- There is one more definition in the STG dump Main.MyDataConstr :: GHC.Types.Int -> Main.MyDataStruct [GblId[DataCon], Arity=1, Caf=NoCafRefs, Str=DmdType <L,U>m, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; -- C-- ------------------------------------------------------------------------- unNewtypeStruct1_rG2_entry() // [R2] { [(cQj, unNewtypeStruct1_rG2_info: const 4294967301; const 0; const 15;)] } {offset cQj: _sQ8::P64 = R2; goto cQl; cQl: R1 = _sQ8::P64 & (-8); call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } Main.unNewtypeStruct_entry() // [R2] { [(cQv, Main.unNewtypeStruct_info: const 4294967301; const 0; const 15;)] } {offset cQv: _B1::P64 = R2; goto cQx; cQx: R2 = _B1::P64; call unNewtypeStruct1_rG2_info(R2) args: 8, res: 0, upd: 8; } } Main.unDataStruct_entry() // [R2] { [(cQJ, block_cQJ_info: const 0; const 32;), (cQM, Main.unDataStruct_info: const 4294967301; const 0; const 15;)] } {offset cQM: _sQ9::P64 = R2; if ((Sp + -8) < SpLim) goto cQN; else goto cQO; cQN: R2 = _sQ9::P64; R1 = Main.unDataStruct_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cQO: I64[Sp - 8] = block_cQJ_info; R1 = _sQ9::P64; Sp = Sp - 8; if (R1 & 7 != 0) goto cQJ; else goto cQK; cQK: call (I64[R1])(R1) returns to cQJ, args: 8, res: 8, upd: 8; cQJ: _sQa::P64 = R1; _sQb::P64 = P64[_sQa::P64 + 7]; R1 = _sQb::P64 & (-8); Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } section ""data" . $tc'MyNewtypeConstr1_rGD_closure" { $tc'MyNewtypeConstr1_rGD_closure: const GHC.Types.TrNameS_static_info; const cRI_str; } section ""data" . Main.$tc'MyNewtypeConstr_closure" { Main.$tc'MyNewtypeConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyNewtypeConstr1_rGD_closure+1; const 10344856529254187725; const 4384341159368653246; const 3; } section ""data" . $tc'MyDataConstr1_rGF_closure" { $tc'MyDataConstr1_rGF_closure: const GHC.Types.TrNameS_static_info; const cRU_str; } section ""data" . Main.$tc'MyDataConstr_closure" { Main.$tc'MyDataConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyDataConstr1_rGF_closure+1; const 12971553621823397951; const 6686958652479025466; const 3; } section ""data" . Main.MyDataConstr_closure" { Main.MyDataConstr_closure: const Main.MyDataConstr_info; } Main.MyDataConstr_entry() // [R2] { [(cSE, Main.MyDataConstr_info: const 4294967301; const 0; const 15;)] } {offset cSE: _B1::P64 = R2; goto cSG; cSG: Hp = Hp + 16; if (Hp > I64[BaseReg + 856]) goto cSI; else goto cSH; cSI: I64[BaseReg + 904] = 16; goto cSF; cSF: R2 = _B1::P64; R1 = Main.MyDataConstr_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cSH: I64[Hp - 8] = Main.MyDataConstr_con_info; P64[Hp] = _B1::P64; _cSD::P64 = Hp - 7; R1 = _cSD::P64; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_con_entry() // [] { [(cSN, Main.MyDataConstr_con_info: const iSP_str-Main.MyDataConstr_con_info; const 1; const 2;)] } {offset cSN: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_static_entry() // [] { [(cSO, Main.MyDataConstr_static_info: const iSQ_str-Main.MyDataConstr_static_info; const 1; const 7;)] } {offset cSO: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } -- LLVM ------------------------------------------------------------------------ %Main_zdtczqMyNewtypeConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyNewtypeConstr_closure$def = internal global %Main_zdtczqMyNewtypeConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGD_closure_struct* @rGD_closure$def to i64),i64 1), i64 -8101887544455363891, i64 4384341159368653246, i64 3}> @Main_zdtczqMyNewtypeConstr_closure = alias i8* bitcast (%Main_zdtczqMyNewtypeConstr_closure_struct* @Main_zdtczqMyNewtypeConstr_closure$def to i8*) %Main_zdtcMyNewtypeStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyNewtypeStruct_closure$def = internal global %Main_zdtcMyNewtypeStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGE_closure_struct* @rGE_closure$def to i64),i64 1), i64 2735651172251469986, i64 2399541496478989519, i64 3}> @Main_zdtcMyNewtypeStruct_closure = alias i8* bitcast (%Main_zdtcMyNewtypeStruct_closure_struct* @Main_zdtcMyNewtypeStruct_closure$def to i8*) %Main_zdtczqMyDataConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyDataConstr_closure$def = internal global %Main_zdtczqMyDataConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGF_closure_struct* @rGF_closure$def to i64),i64 1), i64 -5475190451886153665, i64 6686958652479025466, i64 3}> @Main_zdtczqMyDataConstr_closure = alias i8* bitcast (%Main_zdtczqMyDataConstr_closure_struct* @Main_zdtczqMyDataConstr_closure$def to i8*) %Main_zdtcMyDataStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyDataStruct_closure$def = internal global %Main_zdtcMyDataStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGG_closure_struct* @rGG_closure$def to i64),i64 1), i64 5826051442705447975, i64 -4331072423017222539, i64 3}> @Main_zdtcMyDataStruct_closure = alias i8* bitcast (%Main_zdtcMyDataStruct_closure_struct* @Main_zdtcMyDataStruct_closure$def to i8*) %Main_MyDataConstr_closure_struct = type <{i64}> @Main_MyDataConstr_closure$def = internal global %Main_MyDataConstr_closure_struct<{i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i64)}> @Main_MyDataConstr_closure = alias i8* bitcast (%Main_MyDataConstr_closure_struct* @Main_MyDataConstr_closure$def to i8*) @Main_MyDataConstr_info = internal alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i8*) define internal ghccc void @Main_MyDataConstr_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 4294967301, i64 0, i64 15}> { cW0: ... ret void } @Main_MyDataConstr_con_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i8*) define ghccc void @Main_MyDataConstr_con_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWK_str_struct* @iWK_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i64)),i64 0), i64 1, i64 2}> { ... } @Main_MyDataConstr_static_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i8*) define ghccc void @Main_MyDataConstr_static_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWL_str_struct* @iWL_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i64)),i64 0), i64 1, i64 7}> { ... }



Main_zdtczqMyDataConstr_closure_struct <{I64 ptrtoint(I64にI8 * @ghczmprim_GHCziTypes_TyCon_static_info)は、追加I64()I64 ptrtoint(%のMain_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ DEF I64に、I64 -- CORE ------------------------------------------------------------------------ unNewtypeStruct1_rG2 :: MyNewtypeStruct -> MyNewtypeStruct unNewtypeStruct1_rG2 = \ (ds_dGl :: MyNewtypeStruct) -> ds_dGl unNewtypeStruct :: MyNewtypeStruct -> Int unNewtypeStruct = unNewtypeStruct1_rG2 `cast` (<MyNewtypeStruct>_R -> N:MyNewtypeStruct[0] :: ((MyNewtypeStruct -> MyNewtypeStruct) :: *) ~R# ((MyNewtypeStruct -> Int) :: *)) unDataStruct :: MyDataStruct -> Int unDataStruct = \ (ds_dGj :: MyDataStruct) -> case ds_dGj of _ [Occ=Dead] { MyDataConstr ds1_dGk -> ds1_dGk } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD = MyDataConstr `cast` (Sym N:MyNewtypeStruct[0] -> <MyDataStruct>_R :: ((Int -> MyDataStruct) :: *) ~R# ((MyNewtypeStruct -> MyDataStruct) :: *)) dToNt :: MyDataStruct -> MyNewtypeStruct dToNt = \ (x_awb :: MyDataStruct) -> case x_awb of _ [Occ=Dead] { MyDataConstr y_awc -> y_awc `cast` (Sym N:MyNewtypeStruct[0] :: (Int :: *) ~R# (MyNewtypeStruct :: *)) -- ... $tc'MyNewtypeConstr1_rGD :: TrName $tc'MyNewtypeConstr1_rGD = TrNameS "'MyNewtypeConstr"# $tc'MyDataConstr1_rGF :: TrName $tc'MyDataConstr1_rGF = TrNameS "'MyDataConstr"# -- .. $tcMyNewtypeStruct1_rGE :: TrName $tcMyNewtypeStruct1_rGE = TrNameS "MyNewtypeStruct"# $tcMyDataStruct1_rGG :: TrName $tcMyDataStruct1_rGG = TrNameS "MyDataStruct"# -- ... -- STG ------------------------------------------------------------------------- unNewtypeStruct1_rG2 :: Main.MyNewtypeStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = sat-only \r srt:SRT:[] [ds_sQ7] ds_sQ7; Main.unNewtypeStruct :: Main.MyNewtypeStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] unNewtypeStruct1_rG2 eta_B1; Main.unDataStruct :: Main.MyDataStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [ds_sQ8] case ds_sQ8 of _ [Occ=Dead] { Main.MyDataConstr ds1_sQa [Occ=Once] -> ds1_sQa; }; Main.ntToD :: Main.MyNewtypeStruct -> Main.MyDataStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; Main.dToNt :: Main.MyDataStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [x_sQb] case x_sQb of _ [Occ=Dead] { Main.MyDataConstr y_sQd [Occ=Once] -> y_sQd; }; -- ... constructors seem to be defined exactly the same way for both types ... -- There is one more definition in the STG dump Main.MyDataConstr :: GHC.Types.Int -> Main.MyDataStruct [GblId[DataCon], Arity=1, Caf=NoCafRefs, Str=DmdType <L,U>m, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; -- C-- ------------------------------------------------------------------------- unNewtypeStruct1_rG2_entry() // [R2] { [(cQj, unNewtypeStruct1_rG2_info: const 4294967301; const 0; const 15;)] } {offset cQj: _sQ8::P64 = R2; goto cQl; cQl: R1 = _sQ8::P64 & (-8); call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } Main.unNewtypeStruct_entry() // [R2] { [(cQv, Main.unNewtypeStruct_info: const 4294967301; const 0; const 15;)] } {offset cQv: _B1::P64 = R2; goto cQx; cQx: R2 = _B1::P64; call unNewtypeStruct1_rG2_info(R2) args: 8, res: 0, upd: 8; } } Main.unDataStruct_entry() // [R2] { [(cQJ, block_cQJ_info: const 0; const 32;), (cQM, Main.unDataStruct_info: const 4294967301; const 0; const 15;)] } {offset cQM: _sQ9::P64 = R2; if ((Sp + -8) < SpLim) goto cQN; else goto cQO; cQN: R2 = _sQ9::P64; R1 = Main.unDataStruct_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cQO: I64[Sp - 8] = block_cQJ_info; R1 = _sQ9::P64; Sp = Sp - 8; if (R1 & 7 != 0) goto cQJ; else goto cQK; cQK: call (I64[R1])(R1) returns to cQJ, args: 8, res: 8, upd: 8; cQJ: _sQa::P64 = R1; _sQb::P64 = P64[_sQa::P64 + 7]; R1 = _sQb::P64 & (-8); Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } section ""data" . $tc'MyNewtypeConstr1_rGD_closure" { $tc'MyNewtypeConstr1_rGD_closure: const GHC.Types.TrNameS_static_info; const cRI_str; } section ""data" . Main.$tc'MyNewtypeConstr_closure" { Main.$tc'MyNewtypeConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyNewtypeConstr1_rGD_closure+1; const 10344856529254187725; const 4384341159368653246; const 3; } section ""data" . $tc'MyDataConstr1_rGF_closure" { $tc'MyDataConstr1_rGF_closure: const GHC.Types.TrNameS_static_info; const cRU_str; } section ""data" . Main.$tc'MyDataConstr_closure" { Main.$tc'MyDataConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyDataConstr1_rGF_closure+1; const 12971553621823397951; const 6686958652479025466; const 3; } section ""data" . Main.MyDataConstr_closure" { Main.MyDataConstr_closure: const Main.MyDataConstr_info; } Main.MyDataConstr_entry() // [R2] { [(cSE, Main.MyDataConstr_info: const 4294967301; const 0; const 15;)] } {offset cSE: _B1::P64 = R2; goto cSG; cSG: Hp = Hp + 16; if (Hp > I64[BaseReg + 856]) goto cSI; else goto cSH; cSI: I64[BaseReg + 904] = 16; goto cSF; cSF: R2 = _B1::P64; R1 = Main.MyDataConstr_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cSH: I64[Hp - 8] = Main.MyDataConstr_con_info; P64[Hp] = _B1::P64; _cSD::P64 = Hp - 7; R1 = _cSD::P64; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_con_entry() // [] { [(cSN, Main.MyDataConstr_con_info: const iSP_str-Main.MyDataConstr_con_info; const 1; const 2;)] } {offset cSN: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_static_entry() // [] { [(cSO, Main.MyDataConstr_static_info: const iSQ_str-Main.MyDataConstr_static_info; const 1; const 7;)] } {offset cSO: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } -- LLVM ------------------------------------------------------------------------ %Main_zdtczqMyNewtypeConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyNewtypeConstr_closure$def = internal global %Main_zdtczqMyNewtypeConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGD_closure_struct* @rGD_closure$def to i64),i64 1), i64 -8101887544455363891, i64 4384341159368653246, i64 3}> @Main_zdtczqMyNewtypeConstr_closure = alias i8* bitcast (%Main_zdtczqMyNewtypeConstr_closure_struct* @Main_zdtczqMyNewtypeConstr_closure$def to i8*) %Main_zdtcMyNewtypeStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyNewtypeStruct_closure$def = internal global %Main_zdtcMyNewtypeStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGE_closure_struct* @rGE_closure$def to i64),i64 1), i64 2735651172251469986, i64 2399541496478989519, i64 3}> @Main_zdtcMyNewtypeStruct_closure = alias i8* bitcast (%Main_zdtcMyNewtypeStruct_closure_struct* @Main_zdtcMyNewtypeStruct_closure$def to i8*) %Main_zdtczqMyDataConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyDataConstr_closure$def = internal global %Main_zdtczqMyDataConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGF_closure_struct* @rGF_closure$def to i64),i64 1), i64 -5475190451886153665, i64 6686958652479025466, i64 3}> @Main_zdtczqMyDataConstr_closure = alias i8* bitcast (%Main_zdtczqMyDataConstr_closure_struct* @Main_zdtczqMyDataConstr_closure$def to i8*) %Main_zdtcMyDataStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyDataStruct_closure$def = internal global %Main_zdtcMyDataStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGG_closure_struct* @rGG_closure$def to i64),i64 1), i64 5826051442705447975, i64 -4331072423017222539, i64 3}> @Main_zdtcMyDataStruct_closure = alias i8* bitcast (%Main_zdtcMyDataStruct_closure_struct* @Main_zdtcMyDataStruct_closure$def to i8*) %Main_MyDataConstr_closure_struct = type <{i64}> @Main_MyDataConstr_closure$def = internal global %Main_MyDataConstr_closure_struct<{i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i64)}> @Main_MyDataConstr_closure = alias i8* bitcast (%Main_MyDataConstr_closure_struct* @Main_MyDataConstr_closure$def to i8*) @Main_MyDataConstr_info = internal alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i8*) define internal ghccc void @Main_MyDataConstr_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 4294967301, i64 0, i64 15}> { cW0: ... ret void } @Main_MyDataConstr_con_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i8*) define ghccc void @Main_MyDataConstr_con_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWK_str_struct* @iWK_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i64)),i64 0), i64 1, i64 2}> { ... } @Main_MyDataConstr_static_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i8*) define ghccc void @Main_MyDataConstr_static_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWL_str_struct* @iWL_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i64)),i64 0), i64 1, i64 7}> { ... }



Main_zdtcMyDataStruct_closure_struct <{I64 ptrtoint(I64にI8 * @ghczmprim_GHCziTypes_TyCon_static_info)は、追加I64()I64 ptrtoint(%のMain_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ DEF I64に、I64 -- CORE ------------------------------------------------------------------------ unNewtypeStruct1_rG2 :: MyNewtypeStruct -> MyNewtypeStruct unNewtypeStruct1_rG2 = \ (ds_dGl :: MyNewtypeStruct) -> ds_dGl unNewtypeStruct :: MyNewtypeStruct -> Int unNewtypeStruct = unNewtypeStruct1_rG2 `cast` (<MyNewtypeStruct>_R -> N:MyNewtypeStruct[0] :: ((MyNewtypeStruct -> MyNewtypeStruct) :: *) ~R# ((MyNewtypeStruct -> Int) :: *)) unDataStruct :: MyDataStruct -> Int unDataStruct = \ (ds_dGj :: MyDataStruct) -> case ds_dGj of _ [Occ=Dead] { MyDataConstr ds1_dGk -> ds1_dGk } ntToD :: MyNewtypeStruct -> MyDataStruct ntToD = MyDataConstr `cast` (Sym N:MyNewtypeStruct[0] -> <MyDataStruct>_R :: ((Int -> MyDataStruct) :: *) ~R# ((MyNewtypeStruct -> MyDataStruct) :: *)) dToNt :: MyDataStruct -> MyNewtypeStruct dToNt = \ (x_awb :: MyDataStruct) -> case x_awb of _ [Occ=Dead] { MyDataConstr y_awc -> y_awc `cast` (Sym N:MyNewtypeStruct[0] :: (Int :: *) ~R# (MyNewtypeStruct :: *)) -- ... $tc'MyNewtypeConstr1_rGD :: TrName $tc'MyNewtypeConstr1_rGD = TrNameS "'MyNewtypeConstr"# $tc'MyDataConstr1_rGF :: TrName $tc'MyDataConstr1_rGF = TrNameS "'MyDataConstr"# -- .. $tcMyNewtypeStruct1_rGE :: TrName $tcMyNewtypeStruct1_rGE = TrNameS "MyNewtypeStruct"# $tcMyDataStruct1_rGG :: TrName $tcMyDataStruct1_rGG = TrNameS "MyDataStruct"# -- ... -- STG ------------------------------------------------------------------------- unNewtypeStruct1_rG2 :: Main.MyNewtypeStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = sat-only \r srt:SRT:[] [ds_sQ7] ds_sQ7; Main.unNewtypeStruct :: Main.MyNewtypeStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] unNewtypeStruct1_rG2 eta_B1; Main.unDataStruct :: Main.MyDataStruct -> GHC.Types.Int [GblId[[RecSel]], Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [ds_sQ8] case ds_sQ8 of _ [Occ=Dead] { Main.MyDataConstr ds1_sQa [Occ=Once] -> ds1_sQa; }; Main.ntToD :: Main.MyNewtypeStruct -> Main.MyDataStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; Main.dToNt :: Main.MyDataStruct -> Main.MyNewtypeStruct [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType, Unf=OtherCon []] = \r srt:SRT:[] [x_sQb] case x_sQb of _ [Occ=Dead] { Main.MyDataConstr y_sQd [Occ=Once] -> y_sQd; }; -- ... constructors seem to be defined exactly the same way for both types ... -- There is one more definition in the STG dump Main.MyDataConstr :: GHC.Types.Int -> Main.MyDataStruct [GblId[DataCon], Arity=1, Caf=NoCafRefs, Str=DmdType <L,U>m, Unf=OtherCon []] = \r srt:SRT:[] [eta_B1] Main.MyDataConstr [eta_B1]; -- C-- ------------------------------------------------------------------------- unNewtypeStruct1_rG2_entry() // [R2] { [(cQj, unNewtypeStruct1_rG2_info: const 4294967301; const 0; const 15;)] } {offset cQj: _sQ8::P64 = R2; goto cQl; cQl: R1 = _sQ8::P64 & (-8); call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } Main.unNewtypeStruct_entry() // [R2] { [(cQv, Main.unNewtypeStruct_info: const 4294967301; const 0; const 15;)] } {offset cQv: _B1::P64 = R2; goto cQx; cQx: R2 = _B1::P64; call unNewtypeStruct1_rG2_info(R2) args: 8, res: 0, upd: 8; } } Main.unDataStruct_entry() // [R2] { [(cQJ, block_cQJ_info: const 0; const 32;), (cQM, Main.unDataStruct_info: const 4294967301; const 0; const 15;)] } {offset cQM: _sQ9::P64 = R2; if ((Sp + -8) < SpLim) goto cQN; else goto cQO; cQN: R2 = _sQ9::P64; R1 = Main.unDataStruct_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cQO: I64[Sp - 8] = block_cQJ_info; R1 = _sQ9::P64; Sp = Sp - 8; if (R1 & 7 != 0) goto cQJ; else goto cQK; cQK: call (I64[R1])(R1) returns to cQJ, args: 8, res: 8, upd: 8; cQJ: _sQa::P64 = R1; _sQb::P64 = P64[_sQa::P64 + 7]; R1 = _sQb::P64 & (-8); Sp = Sp + 8; call (I64[R1])(R1) args: 8, res: 0, upd: 8; } } section ""data" . $tc'MyNewtypeConstr1_rGD_closure" { $tc'MyNewtypeConstr1_rGD_closure: const GHC.Types.TrNameS_static_info; const cRI_str; } section ""data" . Main.$tc'MyNewtypeConstr_closure" { Main.$tc'MyNewtypeConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyNewtypeConstr1_rGD_closure+1; const 10344856529254187725; const 4384341159368653246; const 3; } section ""data" . $tc'MyDataConstr1_rGF_closure" { $tc'MyDataConstr1_rGF_closure: const GHC.Types.TrNameS_static_info; const cRU_str; } section ""data" . Main.$tc'MyDataConstr_closure" { Main.$tc'MyDataConstr_closure: const GHC.Types.TyCon_static_info; const Main.$trModule_closure+1; const $tc'MyDataConstr1_rGF_closure+1; const 12971553621823397951; const 6686958652479025466; const 3; } section ""data" . Main.MyDataConstr_closure" { Main.MyDataConstr_closure: const Main.MyDataConstr_info; } Main.MyDataConstr_entry() // [R2] { [(cSE, Main.MyDataConstr_info: const 4294967301; const 0; const 15;)] } {offset cSE: _B1::P64 = R2; goto cSG; cSG: Hp = Hp + 16; if (Hp > I64[BaseReg + 856]) goto cSI; else goto cSH; cSI: I64[BaseReg + 904] = 16; goto cSF; cSF: R2 = _B1::P64; R1 = Main.MyDataConstr_closure; call (I64[BaseReg - 8])(R2, R1) args: 8, res: 0, upd: 8; cSH: I64[Hp - 8] = Main.MyDataConstr_con_info; P64[Hp] = _B1::P64; _cSD::P64 = Hp - 7; R1 = _cSD::P64; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_con_entry() // [] { [(cSN, Main.MyDataConstr_con_info: const iSP_str-Main.MyDataConstr_con_info; const 1; const 2;)] } {offset cSN: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } Main.MyDataConstr_static_entry() // [] { [(cSO, Main.MyDataConstr_static_info: const iSQ_str-Main.MyDataConstr_static_info; const 1; const 7;)] } {offset cSO: R1 = R1 + 1; call (P64[Sp])(R1) args: 8, res: 0, upd: 8; } } -- LLVM ------------------------------------------------------------------------ %Main_zdtczqMyNewtypeConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyNewtypeConstr_closure$def = internal global %Main_zdtczqMyNewtypeConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGD_closure_struct* @rGD_closure$def to i64),i64 1), i64 -8101887544455363891, i64 4384341159368653246, i64 3}> @Main_zdtczqMyNewtypeConstr_closure = alias i8* bitcast (%Main_zdtczqMyNewtypeConstr_closure_struct* @Main_zdtczqMyNewtypeConstr_closure$def to i8*) %Main_zdtcMyNewtypeStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyNewtypeStruct_closure$def = internal global %Main_zdtcMyNewtypeStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGE_closure_struct* @rGE_closure$def to i64),i64 1), i64 2735651172251469986, i64 2399541496478989519, i64 3}> @Main_zdtcMyNewtypeStruct_closure = alias i8* bitcast (%Main_zdtcMyNewtypeStruct_closure_struct* @Main_zdtcMyNewtypeStruct_closure$def to i8*) %Main_zdtczqMyDataConstr_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtczqMyDataConstr_closure$def = internal global %Main_zdtczqMyDataConstr_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGF_closure_struct* @rGF_closure$def to i64),i64 1), i64 -5475190451886153665, i64 6686958652479025466, i64 3}> @Main_zdtczqMyDataConstr_closure = alias i8* bitcast (%Main_zdtczqMyDataConstr_closure_struct* @Main_zdtczqMyDataConstr_closure$def to i8*) %Main_zdtcMyDataStruct_closure_struct = type <{i64, i64, i64, i64, i64, i64}> @Main_zdtcMyDataStruct_closure$def = internal global %Main_zdtcMyDataStruct_closure_struct<{i64 ptrtoint (i8* @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (%Main_zdtrModule_closure_struct* @Main_zdtrModule_closure$def to i64),i64 1), i64 add (i64 ptrtoint (%rGG_closure_struct* @rGG_closure$def to i64),i64 1), i64 5826051442705447975, i64 -4331072423017222539, i64 3}> @Main_zdtcMyDataStruct_closure = alias i8* bitcast (%Main_zdtcMyDataStruct_closure_struct* @Main_zdtcMyDataStruct_closure$def to i8*) %Main_MyDataConstr_closure_struct = type <{i64}> @Main_MyDataConstr_closure$def = internal global %Main_MyDataConstr_closure_struct<{i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i64)}> @Main_MyDataConstr_closure = alias i8* bitcast (%Main_MyDataConstr_closure_struct* @Main_MyDataConstr_closure$def to i8*) @Main_MyDataConstr_info = internal alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_info$def to i8*) define internal ghccc void @Main_MyDataConstr_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 4294967301, i64 0, i64 15}> { cW0: ... ret void } @Main_MyDataConstr_con_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i8*) define ghccc void @Main_MyDataConstr_con_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWK_str_struct* @iWK_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_con_info$def to i64)),i64 0), i64 1, i64 2}> { ... } @Main_MyDataConstr_static_info = alias i8* bitcast (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i8*) define ghccc void @Main_MyDataConstr_static_info$def(i64* noalias nocapture %Base_Arg, i64* noalias nocapture %Sp_Arg, i64* noalias nocapture %Hp_Arg, i64 %R1_Arg, i64 %R2_Arg, i64 %R3_Arg, i64 %R4_Arg, i64 %R5_Arg, i64 %R6_Arg, i64 %SpLim_Arg) align 8 nounwind prefix <{i64, i64, i64}><{i64 add (i64 sub (i64 ptrtoint (%iWL_str_struct* @iWL_str$def to i64),i64 ptrtoint (void (i64*, i64*, i64*, i64, i64, i64, i64, i64, i64, i64)* @Main_MyDataConstr_static_info$def to i64)),i64 0), i64 1, i64 7}> { ... }





PS:もちろん、タイプnewtype N



自体はコンパイル時にどこにも消えることはありません。コンパイルされたモジュールは、他のモジュールで使用するために文字をエクスポートする必要があります。 さらに、この型によって実装されるクラスの関数へのポインタをどこかに保存する必要があります。 newtype



の本当の利点は、低レベルでは、必要な値に到達するためにコンストラクターのチェーンを通過する必要がないことです。







なぜこれが必要なのですか?



前の段落で、可能な場合はデータの代わりにnewtypeを使用する方がよい理由を暗黙的に決定しました(newtypeはより高速でコンパクトです)。 さて、未解決の質問:なぜnewtypeを使用するのか-1つのコンストラクターとフィールドを持つ型-いつ元の型または型シノニムを使用できるのか? これには多くの理由があります。







型推論を理解しやすくする



型の同義語は型の推論中に逆参照され、newtypeは常に別の型です。 次の例を考えてみましょう。







 newtype Height = Height Double newtype Weight = Weight Double newtype Percent = Percent Double newtype Age = Age Int diseaseRate :: Height -> Weight -> Age -> Percent diseaseRate (Height h) (Weight w) = _ diseaseRate' :: Double -> Double -> Int -> Double diseaseRate' hw = _
      
      





コンパイラーの出力:







 Example.hs:19:36: error: • Found hole: _ :: Age -> Percent • ... Example.hs:23:20: error: • Found hole: _ :: Int -> Double • ...
      
      





Int -> Double



よりもInt -> Double



Age -> Percent



必要な機能の種類を理解する方がはるかに簡単です。 有名なレンズライブラリは強力なツールですが、悪夢の中でコンビネータのタイプを分析することを夢見ます。







ドキュメントのヘルプ



非常に単純な理由ですが、何らかの理由で、教科書やチュートリアルではほとんど言及されていません。 前の例では、 diseaseRate'



関数の引数として身長と体重を混在させることは非常に簡単ですが、コンパイラは、 diseaseRate



関数でこれを行うことを許可しません。 もちろん、これはドキュメントをキャンセルしませんが、それに非常に良い追加です。

関数ごとに多数の新しい型を生成したくない場合、便利なテクニックがあります-タグ付けを使用します:







 newtype Tagged tag a = Tagged { unTagged :: a }
      
      





列挙型でタグ付けするか、 GHC.TypeLits



使用GHC.TypeLits



ます。

このトリックを初めて見たのはサイモンマイヤーの講義でした。







実装の詳細を隠す



関心を表示するデータ型としてFloat



またはDouble



を使用していますか? ライブラリユーザーはこれを知らないことがあります(プラットフォームによってタイプが異なる場合があります。または、ライブラリの新しいバージョンで変更する場合があります)。







既存のタイプに新しい動作を実装する



最も一般的な理由。 新しい型を作成することにより、いくつかのクラスを再実装できます。 たとえば、数値の後に「%」記号を付けて行にパーセンテージを出力したい:







 instance Show Percent where show (Percent t) = show t ++ "%"
      
      





しかし、実際には、関心を追加し、増やしたいと思います。 すべてのNum



メソッドなどをオーバーライドしないでください。 このためのGHCには、拡張GeneralizedNewtypeDeriving



があります。これにより、 newtype



型の幅広いクラスの実装を自然に派生させることができます。







 {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Example where newtype Percent = Percent Double deriving (Eq, Ord, Num, Fractional, Floating, Real, RealFrac, RealFloat) instance Show Percent where show (Percent t) = show t ++ "%" x :: Percent x = 2 + Percent 4
      
      







さまざまな理由でnewtype



を使用する例はたくさんあります。 たぶん、 data



よりも頻繁に使用されdata



。 最初の主な例は、もちろんIO



です。 次のコマンドを入力して:info IO



ghci



コンソールで:info IO









 ghci> :info IO newtype IO a = GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #)) -- Defined in 'GHC.Types'
      
      





, IO



newtype



+. , ST

newtype ST sa = ST (STRep sa)



.







transformers

newtype RWST rwsma = RWST { runRWST :: r -> s -> m (a, s, w) }



.







: Data.Semigroup Data.Monoid newtype



- . , ( newtype Max a = Max { getMax :: a }



) Ord



, Ord



Bounded



. !








All Articles