Generics are about sitting between a nominal and structural view of types.
Parametric Polymorphism Vs Types Classes Vs Generics
Parametric Polymorpishm - says behave on all types in exactly same way
on the other hand typeclasses is an interface which behaves differently depending on the type
Generics are in between the two extremes
Haskell has a nominal type system - based on names
Generic programming gets the type system to behave more structurally than nominally
so Generics use associated type families to describe the structure of types by representing their data constructors in the type system.
class Generic a where ... data Colour = Red | Green | Blue instance Generic Colour where type Rep Colour = Either () (Either () ()) -- for going to and from the values to values of the type to the values of the type for our representation of -- the structure of the data types from :: Colour -> Rep Colour from Red = Left () ... to :: Rep Colour -> Colour to ( (Left ()) = Red ...
-- just a marker for attaching names of data constructors to type level
-- n with kind symbol - just a type level string with name of constructor
hs newtype Con (n :: Symbol) a = Con a
Once we add this new type then we rewrite the Generic instance for Colour
instance Generic Colour where type Rep Colour = Either (Con "Red" ()) (Either (Con "Blue" ()) (Con "Green" ()))) -- for going to and from the values to values of the type to the values of the type for our representation of -- the structure of the data types from :: Colour -> Rep Colour from Red = Left ((Con ())) ... to :: Rep Colour -> Colour to ( (Left (Con ())) = Red ...
Now we can create a class for getting the generic constructors name GConName.
gconName just gives us the name of the data constructor which exists at the type level to the value level.
class GConName a where gconName :: a -> String instance KnownSymbol n => GConName (Con n a) where gconName _ = symbolVal (Proxy @n) instance (GConName a, GConName b) -> GConName (Either a b) where gconName (Left a) = gconName a gconName (Right b) = gconName b
Yay so we can get the name now,
This type representation so far isn't great for deriving instances through generics for parameterised types of kind * -> *
Why can't we derive all types as Generics?
GADTs and existentials are very difficult to represent as Generics