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

The Great Power of newtypes

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

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

Avatar for Hiromi Ishii

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.