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 . !



Source: https://habr.com/ru/post/J323526/


All Articles