Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Great Power of newtypes

The Great Power of newtypes

This is the English translation of my Japanese talk at Five Corp, describing newtypes, Foldables and DerivingVia extensions (https://speakerdeck.com/konn/ben-dang-hasugoi-newtype?slide=167).

Hiromi Ishii

August 24, 2018
Tweet

More Decks by Hiromi Ishii

Other Decks in Programming

Transcript

  1. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH module Data.Id (Id ()) where newtype Id =

    MkId Word %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally
  2. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH module Data.Id (Id ()) where newtype Id =

    MkId Word %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally )JEFEBUBDPOTMkId
 outside the module
  3. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH *NQMFNFOUBUJPO4IBSJOH module Data.Id (Id ()) where newtype Id

    = MkId Word %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Id = MkId Word deriving (Num, Eq) )JEFEBUBDPOTMkId
 outside the module
  4. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH *NQMFNFOUBUJPO4IBSJOH module Data.Id (Id ()) where newtype Id

    = MkId Word %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Id = MkId Word deriving (Num, Eq) 6OEFSJWBCMFJO)BTLFMM  CVUXFDBOTIBSFWordTJNQM )JEFEBUBDPOTMkId
 outside the module
  5. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH *NQMFNFOUBUJPO4IBSJOH module Data.Id (Id ()) where newtype Id

    = MkId Word %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Id = MkId Word deriving (Num, Eq) 6OEFSJWBCMFJO)BTLFMM  CVUXFDBOTIBSFWordTJNQM &WPMWFT NPSFJO %FSJWJOH7JB )JEFEBUBDPOTMkId
 outside the module
  6. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH *NQMFNFOUBUJPO4IBSJOH *NQMFNFOUBUJPO4FMFDUJPO module Data.Id (Id ()) where newtype

    Id = MkId Word %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Id = MkId Word deriving (Num, Eq) 6OEFSJWBCMFJO)BTLFMM  CVUXFDBOTIBSFWordTJNQM &WPMWFT NPSFJO %FSJWJOH7JB )JEFEBUBDPOTMkId
 outside the module
  7. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH *NQMFNFOUBUJPO4IBSJOH *NQMFNFOUBUJPO4FMFDUJPO {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Id

    = MkId Word deriving (Num, Eq) 6OEFSJWBCMFJO)BTLFMM  CVUXFDBOTIBSFWordTJNQM &WPMWFT NPSFJO %FSJWJOH7JB module Data.Id (Id ()) where newtype Id = MkId Word )JEFEBUBDPOTMkId
 outside the module
  8. 3PMFTPGnewtypeT *NQMFNFOUBUJPO)JEJOH *NQMFNFOUBUJPO4IBSJOH *NQMFNFOUBUJPO4FMFDUJPO {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Id

    = MkId Word deriving (Num, Eq) 6OEFSJWBCMFJO)BTLFMM  CVUXFDBOTIBSFWordTJNQM &WPMWFT NPSFJO %FSJWJOH7JB module Data.Id (Id ()) where newtype Id = MkId Word )JEFEBUBDPOTMkId
 outside the module %JTUJOHVJTIFEBUUZQFMFWFM  CVUKVTUBWord internally
  9. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) ˞ℕJTTIPSUGPS*OUFHFS
  10. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) 8FIBWFTJNJMBSPQFSBUJPOTPOCPUITJEFT ˞ℕJTTIPSUGPS*OUFHFS
  11. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) 8FIBWFTJNJMBSPQFSBUJPOTPOCPUITJEFT ˞ℕJTTIPSUGPS*OUFHFS
  12. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) 8FIBWFTJNJMBSPQFSBUJPOTPOCPUITJEFT .BQ #JOBSZ 0QFSBUJPO ˞ℕJTTIPSUGPS*OUFHFS
  13. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) 8FIBWFTJNJMBSPQFSBUJPOTPOCPUITJEFT .BQ #JOBSZ 0QFSBUJPO ˞ℕJTTIPSUGPS*OUFHFS
  14. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) 8FIBWFTJNJMBSPQFSBUJPOTPOCPUITJEFT .BQ #JOBSZ 0QFSBUJPO 6OJUT ˞ℕJTTIPSUGPS*OUFHFS
  15. 5ZQJDBM"OTXFS 'PMET aggregate :: [ℕ] " (Maybe ℕ, ℕ) aggregate

    = foldr (λ a (m, s) " (Just a `max` m, a + s)) (Nothing, 0) 8FIBWFTJNJMBSPQFSBUJPOTPOCPUITJEFT .POPJET .BQ #JOBSZ 0QFSBUJPO 6OJUT ˞ℕJTTIPSUGPS*OUFHFS
  16. .POPJET w "OPQFSBUJPOXIJDIDBOCFDPNQVUFECPUI GSPNMFGUBOESJHIU XJUIVOJUFMFNFOU • Both `max` and (+)

    • … can be computed from either left or right, • … has Nothing (no max) and 0 as units. • Mapping to monoid + folding ⤳ Foldable! x ∙ (y ∙ z) = (x ∙ y) ∙ z x ∙ ε = x = ε ∙ x
  17. 'PMEBCMFDMBTT class Foldable t where foldMap :: Monoid m 㱺

    (a " m) " t a " m … .BQUP.POPJE
  'PMEMFGUUPSJHIU
  18. 'PMEBCMFDMBTT *UTV⒏DFTUPNBLFNBY  pUJOUIJTGSBNFXPSL class Foldable t where foldMap ::

    Monoid m 㱺 (a " m) " t a " m … .BQUP.POPJE
  'PMEMFGUUPSJHIU
  19. &YBNQMFJOTUBODFT newtype Sum a = Sum { getSum :: a}

    deriving (Num, Integral) instance Num a 㱺 Monoid (Sum a) where (<>) = (+); ε = 0 newtype Max a = Max { getMax :: a } deriving (Num, Integral, Ord) instance Ord a 㱺 Semigroup (Max a) where (<>) = max
  20. &YBNQMFJOTUBODFT newtype Sum a = Sum { getSum :: a}

    deriving (Num, Integral) instance Num a 㱺 Monoid (Sum a) where (<>) = (+); ε = 0 newtype Max a = Max { getMax :: a } deriving (Num, Integral, Ord) instance Ord a 㱺 Semigroup (Max a) where (<>) = max .POPJEPG OVNFSJDBEEJUJPO
  21. &YBNQMFJOTUBODFT newtype Sum a = Sum { getSum :: a}

    deriving (Num, Integral) instance Num a 㱺 Monoid (Sum a) where (<>) = (+); ε = 0 newtype Max a = Max { getMax :: a } deriving (Num, Integral, Ord) instance Ord a 㱺 Semigroup (Max a) where (<>) = max .POPJEPG OVNFSJDBEEJUJPO 4FNJHSPVQCZ UBLJOHNBY
  22. &YBNQMFJOTUBODFT newtype Sum a = Sum { getSum :: a}

    deriving (Num, Integral) instance Num a 㱺 Monoid (Sum a) where (<>) = (+); ε = 0 newtype Max a = Max { getMax :: a } deriving (Num, Integral, Ord) instance Ord a 㱺 Semigroup (Max a) where (<>) = max .POPJEPG OVNFSJDBEEJUJPO 4FNJHSPVQCZ UBLJOHNBY *NQMTIBSJOHCZ (/%
  23. 1SBDUJDBM3FNBSL w 0OMZCPVOEFEUZQFTDBOCF\max min^NPOPJET 8F OFFENBYJNVNNJOJNVNFMFNFOUUPIBWFUIFVOJU  w 8FTUJMMIBWFB4FNJSJOH XIJDIMBDLTVOJUT

    w 8FIBWFUPDPOWFSUJUUPNPOPJEUPVTFXJUI'PMEBCMF newtype Max a = Max a instance Ord a 㱺 Semigroup (Max a) instance Bounded a 㱺 Monoid (Max a)
  24. 1SBDUJDBM3FNBSL OptionBEKPJOTVOJU UVSOJOHTFNJHSPVQTJOUPNPOPJET ʙ()$ɿ.BZCFSFRVJSFT.POPJEBBTBDPOTUSBJOU ()$ʙɿ3FRVJSFTPOMZSemigroup a, no need of 0QUJPO

    newtype Option a = Option (Maybe a) instance Semigroup a 㱺 Monoid (Option a) instance Monoid a 㱺 Monoid (Maybe a) instance Semigroup a 㱺 Monoid (Maybe a)
  25. 1SBDUJDBM3FNBSL OptionBEKPJOTVOJU UVSOJOHTFNJHSPVQTJOUPNPOPJET ʙ()$ɿ.BZCFSFRVJSFT.POPJEBBTBDPOTUSBJOU ()$ʙɿ3FRVJSFTPOMZSemigroup a, no need of 0QUJPO

    8FTUJMMIBWFUPVTF0QUJPOUPXSJUFBQPSUBCMFDPEFTUIPVHI newtype Option a = Option (Maybe a) instance Semigroup a 㱺 Monoid (Option a) instance Monoid a 㱺 Monoid (Maybe a) instance Semigroup a 㱺 Monoid (Maybe a)
  26. 'PMEBCMFOFXUZQFWFSTJPO import Control.Arrow aggregate :: [ℕ] " (Maybe ℕ, ℕ)

    aggregate = fmap getMax *** getSum ◦ foldMap (Just . Max &&& Sum)
  27. 'PMEBCMFOFXUZQFWFSTJPO 4PDPODJTF import Control.Arrow aggregate :: [ℕ] " (Maybe ℕ,

    ℕ) aggregate = fmap getMax *** getSum ◦ foldMap (Just . Max &&& Sum)
  28. 'PMEBCMFOFXUZQFWFSTJPO 4PDPODJTF *UTTUJMMUFEJPVTUPVOXSBQ.BYBOE4VNUIFZ TJUTJOOFTUFEUZQFT import Control.Arrow aggregate :: [ℕ] "

    (Maybe ℕ, ℕ) aggregate = fmap getMax *** getSum ◦ foldMap (Just . Max &&& Sum) ‎;FSP$PTU$PFSDJPOT
  29. #VU

  30. ;FSP$PTU$PFSDJPO w $PFSDJCMFSFMBUFTUXPUZQFTXJUIUIFTBNFNFNPSZSFQS w *UTFFNTMJLFBUZQFDMBTT CVU()$HFOFSBUFTBOJOGPSNBUJPO BUDPNQJMFUJNF BOEVTFSDBOOPUBEEDVTUPNJOTUBODF w 8JUIcoerceGSPNData.Coerce

    XFDBOEP[FSPDPTUDBTUT w *OGFSSFEQFSNPEVMF XFOFFEUIFJOGPPGEBUBDPOTUSVDUPS UPDBMMcoerce import Data.Coerce (coerce) coerce :: Coercible a b 㱺 a " b
  31. 8JUIDPFSDF import Control.Arrow aggregate :: [ℕ] " (Maybe ℕ, ℕ)

    aggregate = fmap getMax *** getSum ◦ foldMap (Just . Max &&& Sum)
  32. 8FHFUJU import Control.Arrow import Data.Coerce aggregate :: [ℕ] " (Maybe

    ℕ, ℕ) aggregate = coerce ◦ foldMap (Just . Max &&& Sum)
  33. 8FHFUJU import Control.Arrow import Data.Coerce aggregate :: [ℕ] " (Maybe

    ℕ, ℕ) aggregate = coerce ◦ foldMap (Just . Max &&& Sum) $BTUJOH OFTUFE UZQFTXJUI[FSP DPTU
  34. 8FHFUJU import Control.Arrow import Data.Coerce aggregate :: [ℕ] " (Maybe

    ℕ, ℕ) aggregate = coerce ◦ foldMap (Just . Max &&& Sum) coerce :: (Maybe (Max ), Sum ) → (Maybe , ) $BTUJOH OFTUFE UZQFTXJUI[FSP DPTU
  35. 8FHFUJU import Control.Arrow import Data.Coerce aggregate :: [ℕ] " (Maybe

    ℕ, ℕ) aggregate = coerce ◦ foldMap (Just . Max &&& Sum) w /PF⒎FDUPOUIFPGTDBOOJOHTJODFJUT[FSPDPTU coerce :: (Maybe (Max ), Sum ) → (Maybe , ) $BTUJOH OFTUFE UZQFTXJUI[FSP DPTU
  36. 8FHFUJU import Control.Arrow import Data.Coerce aggregate :: [ℕ] " (Maybe

    ℕ, ℕ) aggregate = coerce ◦ foldMap (Just . Max &&& Sum) w /PF⒎FDUPOUIFPGTDBOOJOHTJODFJUT[FSPDPTU w +VTUPOFDBMMGPSDPFSDFUPNBLFJUEPOF coerce :: (Maybe (Max ), Sum ) → (Maybe , ) $BTUJOH OFTUFE UZQFTXJUI[FSP DPTU
  37. $BTUJOHCXOFTUFEUZQFT *UTDPOWFOJFOUUIBUXFDBODBTUBOZOFTUFEUZQFT 3FBMMZ newtype Down a = Down a instance

    Ord a 㱺 Ord (Down a) where a ≤ b = b ≤ a data Heap a minView :: Heap a " Maybe a
  38. $BTUJOHCXOFTUFEUZQFT *UTDPOWFOJFOUUIBUXFDBODBTUBOZOFTUFEUZQFT 3FBMMZ newtype Down a = Down a instance

    Ord a 㱺 Ord (Down a) where a ≤ b = b ≤ a data Heap a minView :: Heap a " Maybe a 3FWFSTFE0SEFS
  39. $BTUJOHCXOFTUFEUZQFT *UTDPOWFOJFOUUIBUXFDBODBTUBOZOFTUFEUZQFT 3FBMMZ newtype Down a = Down a instance

    Ord a 㱺 Ord (Down a) where a ≤ b = b ≤ a data Heap a minView :: Heap a " Maybe a 3FWFSTFE0SEFS )FBQ
  40. $BTUJOHCXOFTUFEUZQFT *UTDPOWFOJFOUUIBUXFDBODBTUBOZOFTUFEUZQFT 3FBMMZ newtype Down a = Down a instance

    Ord a 㱺 Ord (Down a) where a ≤ b = b ≤ a data Heap a minView :: Heap a " Maybe a 3FWFSTFE0SEFS )FBQ .JOJNVN 0 
  41. $BTUJOHCXOFTUFEUZQFT *UTDPOWFOJFOUUIBUXFDBODBTUBOZOFTUFEUZQFT 3FBMMZ newtype Down a = Down a instance

    Ord a 㱺 Ord (Down a) where a ≤ b = b ≤ a data Heap a minView :: Heap a " Maybe a 4FNBOUJDBMMZ Heap a.645/05CFDBTUFEUPHeap (Down a) 3FWFSTFE0SEFS )FBQ .JOJNVN 0 
  42. 3PMFT w 8FDBODBTUUIFNXJUIDPFSDF ghci> h = fromList [1,2,3] :: Heap

    Int ghci> minView (coerce h :: Heap (Down Int)) Just 1
  43. 3PMFT w 8FDBODBTUUIFNXJUIDPFSDF ghci> h = fromList [1,2,3] :: Heap

    Int ghci> minView (coerce h :: Heap (Down Int)) Just 1 .VTUCFJust 3!
  44. 3PMFT w 8FDBODBTUUIFNXJUIDPFSDF ghci> h = fromList [1,2,3] :: Heap

    Int ghci> minView (coerce h :: Heap (Down Int)) Just 1 w 5IFOXFTQFDJGZUIF3PMF .VTUCFJust 3!
  45. 3PMFT w 8FDBODBTUUIFNXJUIDPFSDF type role Heap nominal ghci> h =

    fromList [1,2,3] :: Heap Int ghci> minView (coerce h :: Heap (Down Int)) Just 1 w 5IFOXFTQFDJGZUIF3PMF .VTUCFJust 3!
  46. 3PMFT w 8FDBODBTUUIFNXJUIDPFSDF type role Heap nominal ghci> h =

    fromList [1,2,3] :: Heap Int ghci> minView (coerce h :: Heap (Down Int)) Just 1 w 5IFOXFTQFDJGZUIF3PMF ghci> minView (coerce h :: Heap (Down Int)) error: Couldn't match type ‘Int’ with ‘Down Int’ .VTUCFJust 3!
  47. 3PMFT w 8FDBODBTUUIFNXJUIDPFSDF type role Heap nominal ghci> h =

    fromList [1,2,3] :: Heap Int ghci> minView (coerce h :: Heap (Down Int)) Just 1 w 5IFOXFTQFDJGZUIF3PMF ghci> minView (coerce h :: Heap (Down Int)) error: Couldn't match type ‘Int’ with ‘Down Int’ .VTUCFJust 3! w 8FDBOOPUDPFSDFXJUIPVUUIFJOGPPGOFXUZQFDPOTUSVDUPST
  48. .PSFPO3PMFT w 3PMF5IFUZQFWBSJBCMFIFSFCFIBWFTMJLFUIJT w 5ISFFLJOETrepresentational / nominal / phantom w

    SFQSFRVJWBMFOUJGUIFZIBWFUIFTBNFSFQSFTFOUBUJPO w OPNJOBMNVTUIBWFFYBDUMZUIFTBNFUZQF
  49. .PSFPO3PMFT w 3PMF5IFUZQFWBSJBCMFIFSFCFIBWFTMJLFUIJT w 5ISFFLJOETrepresentational / nominal / phantom w

    SFQSFRVJWBMFOUJGUIFZIBWFUIFTBNFSFQSFTFOUBUJPO w OPNJOBMNVTUIBWFFYBDUMZUIFTBNFUZQF w QIBOUPNVOSFMBUFEUPJUTSFBMDPOUFOUBOZUIJOHHPFT
  50. .PSFPO3PMFT w 3PMF5IFUZQFWBSJBCMFIFSFCFIBWFTMJLFUIJT w 5ISFFLJOETrepresentational / nominal / phantom w

    SFQSFRVJWBMFOUJGUIFZIBWFUIFTBNFSFQSFTFOUBUJPO w OPNJOBMNVTUIBWFFYBDUMZUIFTBNFUZQF w QIBOUPNVOSFMBUFEUPJUTSFBMDPOUFOUBOZUIJOHHPFT w ()$JOGFSTNPTUHFOFSBMSPMFTBUFWFSZUJNF
  51. .PSFPO3PMFT w 3PMF5IFUZQFWBSJBCMFIFSFCFIBWFTMJLFUIJT w 5ISFFLJOETrepresentational / nominal / phantom w

    SFQSFRVJWBMFOUJGUIFZIBWFUIFTBNFSFQSFTFOUBUJPO w OPNJOBMNVTUIBWFFYBDUMZUIFTBNFUZQF w QIBOUPNVOSFMBUFEUPJUTSFBMDPOUFOUBOZUIJOHHPFT w ()$JOGFSTNPTUHFOFSBMSPMFTBUFWFSZUJNF w 4PNFUJNFTMJCSBSZJNQMFNFOUPSNVTUTQFDJGZSPMFT CFDBVTF ()$DBOUUFMMUIFTFNBOUJDTTQFDJpDUPUIFQBSUJDVMBSUZQF
  52. .PSFPO3PMFT w 3PMF5IFUZQFWBSJBCMFIFSFCFIBWFTMJLFUIJT w 5ISFFLJOETrepresentational / nominal / phantom w

    SFQSFRVJWBMFOUJGUIFZIBWFUIFTBNFSFQSFTFOUBUJPO w OPNJOBMNVTUIBWFFYBDUMZUIFTBNFUZQF w QIBOUPNVOSFMBUFEUPJUTSFBMDPOUFOUBOZUIJOHHPFT w ()$JOGFSTNPTUHFOFSBMSPMFTBUFWFSZUJNF w 4PNFUJNFTMJCSBSZJNQMFNFOUPSNVTUTQFDJGZSPMFT CFDBVTF ()$DBOUUFMMUIFTFNBOUJDTTQFDJpDUPUIFQBSUJDVMBSUZQF w 8FDBOUDPFSDFUZQFTXJUIPVOFXUZQFDPOTUSVDUPSJOGP
  53. $PFSDJPO3PMFT4VNNBSZ w 8JUIDPFSDFGVODUJPO XFDBODBTUOFTUUZQFT XJUIUIFTBNFSFQSFTFOUBUJPO XJUI[FSPDPTU w 8FDBOVTFOFXUZQFTNPSFTBGFMZBOE DPOWFOJFOUMZ w

    8FDBODPOUSPMDBTUBCJMJUZCZTQFDJGZJOH3PMFT w 3PMFTBSFVTVBMMZJOGFSSFE w 8FIBWFUPTQFDJGZSPMFTXIFOXFXBOUUP EJTBMMPXDBTUTGPSUIFTFNBOUJDBMSFBTPOT
  54. 1SFIJTUPSZPG;FSP$PTU $PFSDJPO(/%DSJTJT w 8FIBWF(FOFSBMJ[FE/FXUZQF%FSJWJOH (/% BULFBTUBMSFBEZJO()$ w "UUIBUUJNF ()$IBEPOMZBUBNFUZQF TZTUFN

    FWFSZUIJOHXBTpOF w -BUFS UZQFGBNJMJFT ("%5TBOETPPODBNF JOUPUIF()$TUZQFTZTUFNBOE w (/%CFDBNFVOPVOE
  55. (/%XBTVOTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x))
  56. (/%XBTVOTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x)) (/%
  57. (/%XBTVOTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x)) (/% $BTUCXBOZUZQFT
  58. (/%JT6OTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x))
  59. (/%JT6OTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x)) (/%CFDBNFUP VTFDPFSDF
  60. (/%JT6OTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x)) (/%CFDBNFUP VTFDPFSDF ()$JTDMFWFS FOPVHIUPJOGFSa BTOPNJOBM
  61. (/%JT6OTPVOE newtype Id1 a = MkId1 a newtype Id2 a

    = MkId2 (Id1 a) deriving (UnsafeCast b) type family Discern a b type instance Discern (Id1 a) b = a type instance Discern (Id2 a) b = b class UnsafeCast to from where unsafe :: from " Discern from to instance UnsafeCast b (Id1 a) where unsafe (MkId1 x) = x unsafeCoerce :: a " b unsafeCoerce x = unsafe (MkId2 (MkId1 x)) (/%CFDBNFUP VTFDPFSDF ()$JTDMFWFS FOPVHIUPJOGFSa BTOPNJOBM 3FKFDU
  62. &H.POPJETUSVDUVSFPG*E w "TXFIBWFTFFO 8PSEIBWFNVMUJQMFNPOPJEJNQMT w 4VQQPTFXFXBOUUPVTFDIPPTJOHUIFOFXFTU*E .BYJNVN *E BTNPOPJEPQFSBUJPOPO*ET w

    Max WordIBTUIFTBNFSFQSBTId GPSNTBNPOPJEXJUI SFTQFDUUP NBY   {-# LANGUAGE DerivingVia #-} newtype Id = MkId Word deriving (Semigroup, Monoid) via Max Word
  63. &H.POPJETUSVDUVSFPG*E w "TXFIBWFTFFO 8PSEIBWFNVMUJQMFNPOPJEJNQMT w 4VQQPTFXFXBOUUPVTFDIPPTJOHUIFOFXFTU*E .BYJNVN *E BTNPOPJEPQFSBUJPOPO*ET w

    Max WordIBTUIFTBNFSFQSBTId GPSNTBNPOPJEXJUI SFTQFDUUP NBY   w %FSJWJOH7JBDBOMJGUUIJTJNQMBVUPNBUJDBMMZUP*E {-# LANGUAGE DerivingVia #-} newtype Id = MkId Word deriving (Semigroup, Monoid) via Max Word
  64. $PNQMJDBUFE&YBNQMF w 4QFDJpFTUIFFODPEJOHNFUIPEBUUZQFMFWFM w 4UBUJDBMMZBTTVSFTUIBUTBNFFODPEJOHJTVTFEJO'SPN+40/5P+40/ data OtherConfig = OtherConfig {

    otrNameOfProcess :: Maybe String , otrArgsToProcess :: [String] } deriving (Read, Show, Eq, Ord, Generic) deriving (ToJSON, FromJSON) via WithOptions '[ FieldLabelModifier '[CamelTo2 "-"] , ConstructorTagModifier '[CamelTo2 "-"] , OmitNothingFields 'True ] OtherConfig
  65. &YBNQMFPG*TP data Blog = Blog { authors :: [Author] ,

    articles :: [Article] } deriving (Generic) deriving (Semigroup, Monoid) via Blog `SameRepAs` ([Author], Dual [Article]) {- ghci> mconcat [Blog ["1"] ["1"], Blog ["2"] ["3","4"]] Blog {authors = ["1","2"], articles = ["3","4","1"]} -}
  66. &YBNQMFPG*TP DPOU newtype SameRepAs a b = SameRepAs { runSameRepAs

    :: a } type Iso a b = (Generic a, Generic b, Coercible (Rep a ()) (Rep b ())) instance (Semigroup b, Iso a b) 㱺 Semigroup (SameRepAs a b) where SameRepAs a <> SameRepAs b = ... instance (Monoid b, Iso a b) 㱺 Monoid (SameRepAs a b) where mempty = SameRepAs $ toA mempty where toA :: b -> a toA = to . (coerce :: Rep b () -> Rep a ()) . from
  67. %FSJWJOH7JB4VNNBSZ w "WBJMBCMFTJODF()$ w 8FDBOVTFOFXUZQFTUPTQFDJGZUIFJNQMGPS EFSJWJOHDMBVTFT w $PNCJOFEXJUI(FOFSJDT XFDBOFWFOEFSJWFUIF JOTUBODFGSPNJTPNPSQIJDUZQF

    CVUOPU OFDFTTBSJMZSFQSFTFOUBUJPOBMMZFRVBM w "OZPUIFSJTPNPSQIJTNFYQSFTTJCMFBTBUZQF DPOTUSBJOUJTBMTPBQQMJDBCMFUPUIJTUFDIOJRVF
  68. 4VNNBSZ w 5ISFFSPMFTPGOFXUZQFT w *NQMFNFOUBUJPO)JEJOH4IBSJOH4FMFDUJPO w 8JUI%BUB$PFSDF XFDBODBTUSFQSFTFOUBUJPOBMMZ FRVBMMUZQFTXJUI[FSPDPTU w

    5IFOFXUZQF3FWPMVUJPOTUBSUFEIFSF w 8FDBOUSFBUDPNQPVOEUZQFTQSPQFSMZXJUISPMF JOGFSFODFBOEBOOPUBUJPOT
  69. 4VNNBSZ w 5ISFFSPMFTPGOFXUZQFT w *NQMFNFOUBUJPO)JEJOH4IBSJOH4FMFDUJPO w 8JUI%BUB$PFSDF XFDBODBTUSFQSFTFOUBUJPOBMMZ FRVBMMUZQFTXJUI[FSPDPTU w

    5IFOFXUZQF3FWPMVUJPOTUBSUFEIFSF w 8FDBOUSFBUDPNQPVOEUZQFTQSPQFSMZXJUISPMF JOGFSFODFBOEBOOPUBUJPOT w 4JODF()$ %FSJWJOH7JBFOBCMFTVTUPVTF OFXUZQFUPDVTUPNJTFUIFEFSJWJOHDMBVTFT
  70. 3FGFSFODFT 1. J. Breitner, R. A. Eisenberg, S. P. Jones

    and S. Weirich, Safe Zero-cost Coercions for Haskell, ICFP 2014. 2. Baldur Blöndal, Andres Löh and Ryan Scott, Deriving Via: How to Turn Hand-Written Instances into an Anti-Pattern, ICFP18.