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

Data Type Generics: Type Safety Without Boilerplate

Data Type Generics: Type Safety Without Boilerplate

Data Type Generics allows you to write generic functions for many or all algebraic data types in a type safe manner without resorting to code generation. This presentation shows how to do that with a couple of simple completely worked out examples. These were my slides for the PureScript Helsinki goes to Tampere meetup.

Juhana Laurinharju

October 18, 2018
Tweet

Other Decks in Programming

Transcript

  1. Data Type Generics Type Safety Without Boilerplate Juhana Laurinharju Emblica

    Oy October 21, 2018 Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 1 / 33
  2. Algebraic Data Types are Cool data UserType = Regular |

    Admin newtype UserName = UserName String data User = User UserType UserName Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 2 / 33
  3. Type classes give polymorphism instance showUserType :: Show UserType where

    show Regular = "Regular" show Admin = "Admin" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 3 / 33
  4. Type classes give polymorphism instance showUserType :: Show UserType where

    show Regular = "Regular" show Admin = "Admin" instance showUserName :: Show UserName where show (UserName name) = "(UserName " <> name <> ")" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 3 / 33
  5. Type classes give polymorphism instance showUserType :: Show UserType where

    show Regular = "Regular" show Admin = "Admin" instance showUserName :: Show UserName where show (UserName name) = "(UserName " <> name <> ")" instance showUser :: Show User where show (User userType userName) = "(User " <> show userType <> " " <> show userName <> ")" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 3 / 33
  6. But that’s a lot of work Could we somehow look

    at the structure of our types? Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 4 / 33
  7. Anatomy of Algebraic Data Types data Example = Example1 String

    String | Example2 String Int Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 5 / 33
  8. Anatomy of Algebraic Data Types data Example = Example1 String

    String | Example2 String Int Sums Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 5 / 33
  9. Anatomy of Algebraic Data Types data Example = Example1 String

    String | Example2 String Int Sums Contructors Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 5 / 33
  10. Anatomy of Algebraic Data Types data Example = Example1 String

    String | Example2 String Int Sums Contructors Products Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 5 / 33
  11. Encoded as Types Sum data Sum a b = Inl

    a | Inr b Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 6 / 33
  12. Encoded as Types Sum data Sum a b = Inl

    a | Inr b Constructors newtype Constructor (name :: Symbol) a = Constructor a Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 6 / 33
  13. Encoded as Types Sum data Sum a b = Inl

    a | Inr b Constructors newtype Constructor (name :: Symbol) a = Constructor a No Arguments data NoArguments = NoArguments Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 6 / 33
  14. Encoded as Types Sum data Sum a b = Inl

    a | Inr b Constructors newtype Constructor (name :: Symbol) a = Constructor a No Arguments data NoArguments = NoArguments Argument newtype Argument a = Argument a Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 6 / 33
  15. Encoded as Types Sum data Sum a b = Inl

    a | Inr b Constructors newtype Constructor (name :: Symbol) a = Constructor a No Arguments data NoArguments = NoArguments Argument newtype Argument a = Argument a Products data Product a b = Product a b Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 6 / 33
  16. Encoded as Types Sum data Sum a b = Inl

    a | Inr b Constructors newtype Constructor (name :: Symbol) a = Constructor a No Arguments data NoArguments = NoArguments Argument newtype Argument a = Argument a Products data Product a b = Product a b Empty types data NoConstructors Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 6 / 33
  17. To There and Back class Generic a rep | a

    -> rep where to :: rep -> a from :: a -> rep Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 7 / 33
  18. To There and Back class Generic a rep | a

    -> rep where to :: rep -> a from :: a -> rep Compiler can generate you instances Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 7 / 33
  19. To There and Back class Generic a rep | a

    -> rep where to :: rep -> a from :: a -> rep Compiler can generate you instances derive instance genericMyType :: Generic MyType _ Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 7 / 33
  20. To There and Back class Generic a rep | a

    -> rep where to :: rep -> a from :: a -> rep Compiler can generate you instances derive instance genericMyType :: Generic MyType _ But we should check out some examples Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 7 / 33
  21. Extremely Simple Type data Simple = Simple Juhana Laurinharju (Emblica

    Oy) Data Type Generics October 21, 2018 8 / 33
  22. Extremely Simple Type data Simple = Simple instance genericSimple ::

    Generic Simple (Constructor "Simple" NoArguments) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 8 / 33
  23. Extremely Simple Type data Simple = Simple instance genericSimple ::

    Generic Simple (Constructor "Simple" NoArguments) where from Simple = Constructor NoArguments Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 8 / 33
  24. Extremely Simple Type data Simple = Simple instance genericSimple ::

    Generic Simple (Constructor "Simple" NoArguments) where from Simple = Constructor NoArguments to (Constructor NoArguments) = Simple Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 8 / 33
  25. Simple Sum Type data Vote = Positive | Negative Juhana

    Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 9 / 33
  26. Simple Sum Type data Vote = Positive | Negative instance

    genericVote :: Generic Vote (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 9 / 33
  27. Simple Sum Type data Vote = Positive | Negative instance

    genericVote :: Generic Vote (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) where from Positive = Inl (Constructor NoArguments) from Negative = Inr (Constructor NoArguments) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 9 / 33
  28. Simple Sum Type data Vote = Positive | Negative instance

    genericVote :: Generic Vote (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) where from Positive = Inl (Constructor NoArguments) from Negative = Inr (Constructor NoArguments) to (Inl (Constructor NoArguments)) = Positive to (Inr (Constructor NoArguments)) = Negative Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 9 / 33
  29. Simple Product Type data Vec3 = Vec3 Number Number Number

    Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 10 / 33
  30. Simple Product Type data Vec3 = Vec3 Number Number Number

    instance genericVec3 :: Generic Vec3 (Constructor "Vec3" (Product (Argument Number) (Product (Argument Number) (Argument Number)))) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 10 / 33
  31. Simple Product Type data Vec3 = Vec3 Number Number Number

    instance genericVec3 :: Generic Vec3 (Constructor "Vec3" (Product (Argument Number) (Product (Argument Number) (Argument Number)))) where from (Vec3 a b c) = Constructor (Product (Argument a) (Product (Argument b) (Argument c))) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 10 / 33
  32. Simple Product Type data Vec3 = Vec3 Number Number Number

    instance genericVec3 :: Generic Vec3 (Constructor "Vec3" (Product (Argument Number) (Product (Argument Number) (Argument Number)))) where from (Vec3 a b c) = Constructor (Product (Argument a) (Product (Argument b) (Argument c))) to (Constructor (Product (Argument a) (Product (Argument b) (Argument c)))) = Vec3 a b c Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 10 / 33
  33. Sum of Products data Example = Example1 String String |

    Example2 String Int Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 11 / 33
  34. Sum of Products data Example = Example1 String String |

    Example2 String Int instance genericExample :: Generic Example (Sum (Constructor "Example1" (Product (Argument String) (Argument String))) (Constructor "Example2" (Product (Argument String) (Argument Int)))) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 11 / 33
  35. Sum of Products data Example = Example1 String String |

    Example2 String Int instance genericExample :: Generic Example (Sum (Constructor "Example1" (Product (Argument String) (Argument String))) (Constructor "Example2" (Product (Argument String) (Argument Int)))) where from (Example1 str1 str2) = (Inl (Constructor (Product (Argument str1) (Argument str2)))) from (Example2 str int) = (Inr (Constructor (Product (Argument str) (Argument int)))) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 11 / 33
  36. Sum of Products data Example = Example1 String String |

    Example2 String Int instance genericExample :: Generic Example (Sum (Constructor "Example1" (Product (Argument String) (Argument String))) (Constructor "Example2" (Product (Argument String) (Argument Int)))) where from (Example1 str1 str2) = (Inl (Constructor (Product (Argument str1) (Argument str2)))) from (Example2 str int) = (Inr (Constructor (Product (Argument str) (Argument int)))) to (Inl (Constructor (Product (Argument str1) (Argument str2)))) = Example1 str1 str2 to (Inr (Constructor (Product (Argument str) (Argument int)))) = Example2 str int Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 11 / 33
  37. Using generic functions There are functions that work with these

    generic representations Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  38. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  39. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  40. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") > log $ genericShow' $ from $ Just "Tampere" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  41. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") > log $ genericShow' $ from $ Just "Tampere" (Just "Tampere") Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  42. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") > log $ genericShow' $ from $ Just "Tampere" (Just "Tampere") And they are type checked Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  43. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") > log $ genericShow' $ from $ Just "Tampere" (Just "Tampere") And they are type checked newtype NoShow a = NoShow a Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  44. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") > log $ genericShow' $ from $ Just "Tampere" (Just "Tampere") And they are type checked newtype NoShow a = NoShow a > log $ genericShow' $ from $ Just (NoShow "Tampere") Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  45. Using generic functions There are functions that work with these

    generic representations > log $ genericShow' $ from $ Example1 "Hello" "Tampere" (Example1 "Hello" "Tampere") > log $ genericShow' $ from $ Just "Tampere" (Just "Tampere") And they are type checked newtype NoShow a = NoShow a > log $ genericShow' $ from $ Just (NoShow "Tampere") No type class instance was found for Data.Show.Show (NoShow String) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 12 / 33
  46. Shape of ADTs Sum (Constructor "Name1" NoArguments) (Sum (Constructor "Name2"

    (Argument Int)) (Constructor "Name3" (Product (Argument String) (Argument Number)))) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 13 / 33
  47. Shape of ADTs Sum (Constructor "Name1" NoArguments) (Sum (Constructor "Name2"

    (Argument Int)) (Constructor "Name3" (Product (Argument String) (Argument Number)))) Sum of Constructor of NoArguments a single Argument Product of Arguments NoConstructors Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 13 / 33
  48. How to Write Such a Function? Constructor, Sum, Product, Argument,

    NoArguments and NoConstructors are all different types Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 14 / 33
  49. How to Write Such a Function? Constructor, Sum, Product, Argument,

    NoArguments and NoConstructors are all different types How to write a function that possibly works on all of them? Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 14 / 33
  50. How to Write Such a Function? Constructor, Sum, Product, Argument,

    NoArguments and NoConstructors are all different types How to write a function that possibly works on all of them? Typeclasses Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 14 / 33
  51. Eq class GenericEq a where genericEq' :: a -> a

    -> Boolean Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 15 / 33
  52. Eq class GenericEq a where genericEq' :: a -> a

    -> Boolean instance genericEqNoArguments :: GenericEq NoArguments where genericEq' NoArguments NoArguments = true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 15 / 33
  53. Eq class GenericEq a where genericEq' :: a -> a

    -> Boolean instance genericEqNoArguments :: GenericEq NoArguments where genericEq' NoArguments NoArguments = true instance genericEqConstructor :: GenericEq args => GenericEq (Constructor name args) where genericEq' (Constructor x) (Constructor y) = genericEq' x y Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 15 / 33
  54. Eq class GenericEq a where genericEq' :: a -> a

    -> Boolean instance genericEqNoArguments :: GenericEq NoArguments where genericEq' NoArguments NoArguments = true instance genericEqConstructor :: GenericEq args => GenericEq (Constructor name args) where genericEq' (Constructor x) (Constructor y) = genericEq' x y > genericEq' (from Simple) (from Simple) true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 15 / 33
  55. Cannot Handle Sums yet > genericEq' (from Negative) (from Negative)

    No type class instance was found for Main.GenericEq (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 16 / 33
  56. Simple Sums instance genericEqSum :: (GenericEq a, GenericEq b) =>

    GenericEq (Sum a b) where genericEq' (Inl x) (Inl y) = genericEq' x y genericEq' (Inr x) (Inr y) = genericEq' x y genericEq' _ _ = false Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 17 / 33
  57. Simple Sums instance genericEqSum :: (GenericEq a, GenericEq b) =>

    GenericEq (Sum a b) where genericEq' (Inl x) (Inl y) = genericEq' x y genericEq' (Inr x) (Inr y) = genericEq' x y genericEq' _ _ = false > genericEq' (from Positive) (from Positive) true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 17 / 33
  58. Simple Sums instance genericEqSum :: (GenericEq a, GenericEq b) =>

    GenericEq (Sum a b) where genericEq' (Inl x) (Inl y) = genericEq' x y genericEq' (Inr x) (Inr y) = genericEq' x y genericEq' _ _ = false > genericEq' (from Positive) (from Positive) true > genericEq' (from Positive) (from Negative) false Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 17 / 33
  59. Argument > genericEq' (from (UserName "KEKKONEN_3000")) (from (UserName "KEKKONEN_3000")) No

    type class instance was found for Main.GenericEq (Argument String) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 18 / 33
  60. Argument instance genericEqArgument :: Eq arg => GenericEq (Argument arg)

    where genericEq' (Argument x) (Argument y) = x == y Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 19 / 33
  61. Argument instance genericEqArgument :: Eq arg => GenericEq (Argument arg)

    where genericEq' (Argument x) (Argument y) = x == y > genericEq' (from (UserName "KEKKONEN_3000")) (from (UserName "KEKKONEN_3000")) true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 19 / 33
  62. Argument instance genericEqArgument :: Eq arg => GenericEq (Argument arg)

    where genericEq' (Argument x) (Argument y) = x == y > genericEq' (from (UserName "KEKKONEN_3000")) (from (UserName "KEKKONEN_3000")) true > genericEq' (from (UserName "Alice")) (from (UserName "Bob")) false Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 19 / 33
  63. Product of Arguments > genericEq' (from (Example2 "Alice" 1)) (from

    (Example2 "Bob" 1)) No type class instance was found for Main.GenericEq (Product (Argument String) (Argument String)) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 20 / 33
  64. Product of Arguments instance genericEqProduct :: (GenericEq a, GenericEq b)

    => GenericEq (Product a b) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 21 / 33
  65. Product of Arguments instance genericEqProduct :: (GenericEq a, GenericEq b)

    => GenericEq (Product a b) where genericEq' (Product x1 y1) (Product x2 y2) = genericEq' x1 x2 && genericEq' y1 y2 Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 21 / 33
  66. Product of Arguments instance genericEqProduct :: (GenericEq a, GenericEq b)

    => GenericEq (Product a b) where genericEq' (Product x1 y1) (Product x2 y2) = genericEq' x1 x2 && genericEq' y1 y2 > genericEq' (from (Example2 "Alice" 1)) (from (Example2 "Bob" 1)) false Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 21 / 33
  67. Product of Arguments instance genericEqProduct :: (GenericEq a, GenericEq b)

    => GenericEq (Product a b) where genericEq' (Product x1 y1) (Product x2 y2) = genericEq' x1 x2 && genericEq' y1 y2 > genericEq' (from (Example2 "Alice" 1)) (from (Example2 "Bob" 1)) false > genericEq' (from (Example2 "Alice" 1)) (from (Example2 "Alice" 1)) true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 21 / 33
  68. Stare in to the Void Should also cover empty types

    instance genericEqNoConstructors :: GenericEq NoConstructors where genericEq' _ _ = true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 22 / 33
  69. Helper function To actually use this, write a helper function

    to do the generic conversion genericEq :: forall a rep . Generic a rep => GenericEq rep => a -> a -> Boolean genericEq x y = genericEq' (from x) (from y) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 23 / 33
  70. User code Now with all of this done, all that

    a user needs to do is write an instance that calls genericEq instance eqExample :: Eq Example where eq = genericEq Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 24 / 33
  71. User code Now with all of this done, all that

    a user needs to do is write an instance that calls genericEq instance eqExample :: Eq Example where eq = genericEq > (Example2 "KEKKONEN_3000" 10) == (Example2 "KEKKONEN_3000" 10) true Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 24 / 33
  72. User code Now with all of this done, all that

    a user needs to do is write an instance that calls genericEq instance eqExample :: Eq Example where eq = genericEq > (Example2 "KEKKONEN_3000" 10) == (Example2 "KEKKONEN_3000" 10) true > (Example2 "KEKKONEN_3000" 10) == (Example1 "KEKKONEN_3000" "10") false Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 24 / 33
  73. Show must go on class GenericShow a where genericShow' ::

    a -> String Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 25 / 33
  74. Show must go on class GenericShow a where genericShow' ::

    a -> String instance genericShowConstructorNoArguments :: IsSymbol name => GenericShow (Constructor name NoArguments) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 25 / 33
  75. Show must go on class GenericShow a where genericShow' ::

    a -> String instance genericShowConstructorNoArguments :: IsSymbol name => GenericShow (Constructor name NoArguments) where genericShow' (Constructor NoArguments) = let constructorNameProxy = SProxy :: SProxy name constructorName = reflectSymbol constructorNameProxy in constructorName Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 25 / 33
  76. Show must go on class GenericShow a where genericShow' ::

    a -> String instance genericShowConstructorNoArguments :: IsSymbol name => GenericShow (Constructor name NoArguments) where genericShow' (Constructor NoArguments) = let constructorNameProxy = SProxy :: SProxy name constructorName = reflectSymbol constructorNameProxy in constructorName > log $ genericShow' $ from Simple Simple Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 25 / 33
  77. Sums > log $ genericShow' $ from Positive No type

    class instance was found for Main.GenericShow (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 26 / 33
  78. Sums > log $ genericShow' $ from Positive No type

    class instance was found for Main.GenericShow (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) instance genericShowSum :: (GenericShow a, GenericShow b) => GenericShow (Sum a b) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 26 / 33
  79. Sums > log $ genericShow' $ from Positive No type

    class instance was found for Main.GenericShow (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) instance genericShowSum :: (GenericShow a, GenericShow b) => GenericShow (Sum a b) where genericShow' (Inl x) = genericShow' x genericShow' (Inr y) = genericShow' y Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 26 / 33
  80. Sums > log $ genericShow' $ from Positive No type

    class instance was found for Main.GenericShow (Sum (Constructor "Positive" NoArguments) (Constructor "Negative" NoArguments)) instance genericShowSum :: (GenericShow a, GenericShow b) => GenericShow (Sum a b) where genericShow' (Inl x) = genericShow' x genericShow' (Inr y) = genericShow' y > log $ genericShow' $ from Positive Positive Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 26 / 33
  81. Single Argument > log $ genericShow' $ from (Just "Tampere")

    No type class instance was found for Main.GenericShow (Constructor "Just" (Argument String)) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 27 / 33
  82. Single Argument > log $ genericShow' $ from (Just "Tampere")

    No type class instance was found for Main.GenericShow (Constructor "Just" (Argument String)) instance genericShowConstructorArgument :: (Show arg, IsSymbol name) => GenericShow (Constructor name (Argument arg)) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 27 / 33
  83. Single Argument > log $ genericShow' $ from (Just "Tampere")

    No type class instance was found for Main.GenericShow (Constructor "Just" (Argument String)) instance genericShowConstructorArgument :: (Show arg, IsSymbol name) => GenericShow (Constructor name (Argument arg)) where genericShow' (Constructor (Argument arg)) = let constructorName = reflectSymbol (SProxy :: SProxy name) argStr = show arg in "(" <> constructorName <> " " <> argStr <> ")" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 27 / 33
  84. Single Argument > log $ genericShow' $ from (Just "Tampere")

    No type class instance was found for Main.GenericShow (Constructor "Just" (Argument String)) instance genericShowConstructorArgument :: (Show arg, IsSymbol name) => GenericShow (Constructor name (Argument arg)) where genericShow' (Constructor (Argument arg)) = let constructorName = reflectSymbol (SProxy :: SProxy name) argStr = show arg in "(" <> constructorName <> " " <> argStr <> ")" > log $ genericShow' $ from (Just "Tampere") (Just "Tampere") Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 27 / 33
  85. Multiple Arguments instance genericShowConstructorProduct :: (IsSymbol name, ??? a, ???

    b) => GenericShow (Constructor name (Product a b)) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 28 / 33
  86. Helper Function to the Rescue class GenericShowArgs a where genericShowArgs

    :: a -> Array String Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 29 / 33
  87. Helper Function to the Rescue class GenericShowArgs a where genericShowArgs

    :: a -> Array String Turn a product of arguments to an array of string Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 29 / 33
  88. Helper Function to the Rescue class GenericShowArgs a where genericShowArgs

    :: a -> Array String Turn a product of arguments to an array of string instance genericShowArgsArgument :: Show a => GenericShowArgs (Argument a) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 29 / 33
  89. Helper Function to the Rescue class GenericShowArgs a where genericShowArgs

    :: a -> Array String Turn a product of arguments to an array of string instance genericShowArgsArgument :: Show a => GenericShowArgs (Argument a) where genericShowArgs (Argument x) = [show x] Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 29 / 33
  90. Helper Function to the Rescue class GenericShowArgs a where genericShowArgs

    :: a -> Array String Turn a product of arguments to an array of string instance genericShowArgsArgument :: Show a => GenericShowArgs (Argument a) where genericShowArgs (Argument x) = [show x] instance genericShowArgsProduct :: (GenericShowArgs a, GenericShowArgs b) => GenericShowArgs (Product a b) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 29 / 33
  91. Helper Function to the Rescue class GenericShowArgs a where genericShowArgs

    :: a -> Array String Turn a product of arguments to an array of string instance genericShowArgsArgument :: Show a => GenericShowArgs (Argument a) where genericShowArgs (Argument x) = [show x] instance genericShowArgsProduct :: (GenericShowArgs a, GenericShowArgs b) => GenericShowArgs (Product a b) where genericShowArgs (Product x y) = genericShowArgs x <> genericShowArgs y Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 29 / 33
  92. Multiple Arguments instance genericShowConstructorProduct :: (IsSymbol name, GenericShowArgs (Product a

    b)) => GenericShow (Constructor name (Product a b)) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 30 / 33
  93. Multiple Arguments instance genericShowConstructorProduct :: (IsSymbol name, GenericShowArgs (Product a

    b)) => GenericShow (Constructor name (Product a b)) where genericShow' (Constructor prod) = let constructorName = reflectSymbol (SProxy :: SProxy name) args = genericShowArgs prod argStr = intercalate " " args in "(" <> constructorName <> " " <> argStr <> ")" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 30 / 33
  94. Multiple Arguments instance genericShowConstructorProduct :: (IsSymbol name, GenericShowArgs (Product a

    b)) => GenericShow (Constructor name (Product a b)) where genericShow' (Constructor prod) = let constructorName = reflectSymbol (SProxy :: SProxy name) args = genericShowArgs prod argStr = intercalate " " args in "(" <> constructorName <> " " <> argStr <> ")" > log $ genericShow' $ from (Example2 "hep" 2) (Example2 "hep" 2) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 30 / 33
  95. Simplified instance genericShowArgsNoArguments :: GenericShowArgs NoArguments where genericShowArgs NoArguments =

    [] Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 31 / 33
  96. Simplified instance genericShowArgsNoArguments :: GenericShowArgs NoArguments where genericShowArgs NoArguments =

    [] instance genericShowConstructor :: (GenericShowArgs params, IsSymbol name) => GenericShow (Constructor name params) where Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 31 / 33
  97. Simplified instance genericShowArgsNoArguments :: GenericShowArgs NoArguments where genericShowArgs NoArguments =

    [] instance genericShowConstructor :: (GenericShowArgs params, IsSymbol name) => GenericShow (Constructor name params) where genericShow' (Constructor args) = let constructorNameProxy = SProxy :: SProxy name constructorName = reflectSymbol constructorNameProxy paramsStringArray = genericShowArgs args in case paramsStringArray of [] -> constructorName someArgs -> "(" <> constructorName <> " " <> (intercalate " " someArgs) <> ")" Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 31 / 33
  98. Helpers genericShow :: forall a rep . Generic a rep

    => GenericShow rep => a -> String genericShow x = genericShow' (from x) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 32 / 33
  99. Helpers genericShow :: forall a rep . Generic a rep

    => GenericShow rep => a -> String genericShow x = genericShow' (from x) instance showExample :: Show Example where show = genericShow Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 32 / 33
  100. Helpers genericShow :: forall a rep . Generic a rep

    => GenericShow rep => a -> String genericShow x = genericShow' (from x) instance showExample :: Show Example where show = genericShow > log $ show $ (Example2 "hep" 2) (Example2 "hep" 2) Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 32 / 33
  101. Recap Sum of Constructor of NoArguments a single Argument Product

    of Arguments NoContructors Juhana Laurinharju (Emblica Oy) Data Type Generics October 21, 2018 33 / 33