📜 ⬆️ ⬇️

Magic newtype in haskell


The main way to set a new data type in Haskell is to use the data construct. However, there is also a newtype . Practicing Haskell programmers use the newtype construct all the time, the popular hlint hlint suggests replacing data with newtype if possible.


But why?



At first I planned this article for newbies. Indeed, the newtype construct is mentioned in the first chapters of Haskell tutorials. It seems to be a simple idea: we limit the presentation for the data type and gain speed. In various sources you can find references that newtype saves on nesting of pointers. But I didn’t find a detailed analysis of what actually happens with this construction in the compiler and why it is so cool and necessary. To fill these gaps, I decided to write an article on Habr.


So, we need the haskell stack and basic knowledge of the Haskell and GHC execution model (we know what lazy calculations are, thunks (uncomputed objects), we heard a little about the stack and the GHC heap).


Semantics


The syntax for the newtype construct is exactly the same as the data construct, except that a newtype can have only one constructor and only one boxed (boxed type) field inside.


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

By the way, all sorts of record syntax and phantom types also work:


 newtype MyFunnyA abc = MyFunnyA { getA :: a } 

But what is the difference between MyValDL ( MyValDS ) and MyValN ?


The Haskell'98 report states that the newtype construct introduces a new type, whose representation is identical to the existing one. That is, Int and MyValN isomorphic. But is it not so for data types? It turns out no. The fact is that in Haskell there are “lifted” and “not lifted” types. For all types declared with data , an additional element "bottom" (bottom, or) is added - they become raised (for the program, the "bottom" is undefined ). This means that " MyValDLC ⊥ :: MyValDL " and " ⊥ :: MyValDL " are different meanings. Unlike data , a newtype type is not raised (unlifted type), which means ⊥ :: MyValN “borrowed” from a nested type (via MyValN ⊥ ).


We can say that for a compiler, a raised type means an extra layer of pointers (a pointer can refer to an embedded object, or to the bottom (undefined)). For a programmer, this means that if the data field of the constructor may contain undefined , all is not lost: until we touch this field, the program will not break. A non-computed field, on the other hand, can be a place of memory leakage (a series of thunks). With strict MyValDS the situation is a bit more complicated: it seems that MyValDSC ⊥ immediately computed to ⊥ , but the semantics of these two constructors are the same. By the way, therefore, professionals recommend declaring all fields in data constructors to be strict, unless there is a real need to use the field lazily - this way you can avoid long hours of searching for memory leaks.


The Haskell wiki has an excellent set of examples that illustrate the difference between data and newtype ; I will give them here, adjusted for free translation and my type names:


 --    (  ), --     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 

The above description is my interpretation of the Haskell wiki . But we will not stop at this and consider a few more questions.


How does it work?


Requiring the same representation of the original type and its newtype wrapper for the compiler means that:



GHC works with types on two levels: Haskell’s “visible” type system, and representation types. The visible type system is what we work with in Haskell programming. However, at some point, the compiler converts the Haskell types into a machine representation. It often happens that two different types in Haskell can have the same representation in machine code. In the modern GHC, with the help of the role system , it is possible to compare types not only nominally, but also according to their presentation. This made it possible to implement the free type conversion mechanism (visible only at the level of the Haskell type system) in the Data.Type.Coercion and Data.Coerce modules .


Considering the above, the general idea of ​​implementing newtype is obvious: all of the packed values ​​in Haskell are represented as a description with a pointer to the constructor (object info tables); therefore, the value of a newtype can in its description use a pointer directly to the constructor of the nested value; it turns out something like the type synonyms, only at a lower level.



Every Haskell programmer knows that GHC does not compile the source code into an assembler right away, but produces a complex series of code conversions in several stages, with optimizations on almost every one of them. First, the Haskell syntax tree is transformed into a simplified version of the language - GHC Core (which is based on system F). Then Core is converted to a functional STG (Spineless Tagless G-machine), then to an imperative C-- (special intermediate language with support for exception handling and garbage collection), and from there to various ways into an assembler.


It seems that the statement that newtype constructors "disappear" at run time is well known. However, it turned out to be quite difficult to understand how this happens. The description of the STG on the GHC website makes us understand that the STG already operates with only representative types, that is, the newtype should be lost to it. Another GHC wiki page hints that some types are always visible, and some only for type checker (the latter, by the way, seem to have the tc prefix at different levels of the generated code). To find out for sure what happens with newtype types, I decided to look at all the intermediate stages of the compiled code with the following example:


 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 

The result was not long in coming at the first stage:


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

The ghc-core program, available in the hackage package of the same name, displays a slightly cleaned GHC Core. Already at this stage, all occurrences of MyNewtypeConstr are replaced by cast operations, while MyDataConstr honestly remains in its place:


 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 :: *)) 

The next stage is STG, it can be viewed with the following command:


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

It is not much different from Core, except for the interesting detail: Main.MyDataConstr is defined explicitly in the generated code, and 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]; 

At the -- level, you can find constructions such as Main.$tc'MyNewtypeConstr and Main.$tc'MyDataConstr , but Main.MyDataConstr does not find a newtype . Apparently, $tc (from the word Type Checker) is another hint of types that are used only at the type checking level.


As we can see, already at the GHC Core transformation stage, newtype constructors are replaced with primitive type conversions. At the C-- level, you can compare the low-level imperative code Main.unNewtypeStruct_entry() and Main.unDataStruct_entry() to make sure that unNewtypeStruct does virtually nothing, unlike unDataStruct .
All output levels can be viewed using several commands:


 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 

The output formatted by me is under a cat. I left only more or less interesting parts (the text is already too much).


Phased GHC output
 -- 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 (i8 * @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (% Main_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ def to 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}> { ... } % -- 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 (i8 * @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (% Main_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ def to 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}> { ... } % -- 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 (i8 * @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (% Main_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ def to 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}> { ... } % -- 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 (i8 * @ghczmprim_GHCziTypes_TyCon_static_info to i64), i64 add (i64 ptrtoint (% Main_zdtrModule_closure_struct * @ Main_zdtrModule_closure $ def to 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}> { ... } % -- 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: Of course, the type newtype N itself cannot disappear anywhere during compilation: a compiled module must export characters for use in other modules. In addition, you need somewhere to store pointers to the functions of the classes implemented by this type. The real benefit of a newtype is that at a low level it is not necessary to go through a chain of constructors to get to the desired value.


And why is this necessary?


In the previous paragraph, we implicitly determined why it is better to use newtype instead of data where it is possible (newtype is faster and more compact). Now the unresolved question is: why bother to use newtype — a type with one constructor and a field — when can I just use the original type or type is a synonym for it? There are many reasons for this.


Easier to understand type inference


Type synonyms are dereferenced during type inference, and newtype is always a separate type. Consider the following example:


 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 = _ 

And the output of the compiler:


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

It is much easier to understand what type the function Age -> Percent should have, than Int -> Double . The famous lens library is a powerful tool, but I often dream about the types of its combinators in nightmares.


Documentation Assistance


A very simple reason, but for some reason it is rarely mentioned in textbooks and tutorials. In the previous example, it is very easy to confuse height and weight as arguments of the diseaseRate' function, but the compiler will not allow this to be done in the diseaseRate function. Of course, this does not cancel the documentation, but is a very good addition to it.
If you do not want to produce a large number of new types for each function, there is a convenient technique - use tagging:


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

You can tag enumerated types, or just use GHC.TypeLits .
The first time I saw this reception was at the lecture of Simon Meyer .


Hiding implementation details


Do we use Float or Double as the data type for percent output? Sometimes, the library user should not know this (the type may differ for different platforms, or we want to change it in a new version of the library).


Implement a new behavior for an existing type.


The most popular reason. Creating a new type, we can implement some classes in a new way. For example, I want to display percentages in the line with the sign "%" after the number:


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

But, generally, I would like to add and multiply the percentages; preferably without the need to override all Num methods and the like. In GHC, for this there is an extension GeneralizedNewtypeDeriving , which allows you to naturally display the implementation of a wide range of classes for newtype types:


 {-# 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 

Examples


There are many examples of using newtype for various reasons. Maybe it is used even more often than data . The first and foremost example is, of course, IO . Just type in the ghci console command :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/323526/


All Articles