Have you ever written boilerplate when implementing an instance for a type class (e.g.
Show) and thought, "Surely, there must be a better/faster way!" Generics is the answer to your problems.
Here's the basic idea behind Generics:
- You, the end developer, define a data type in your application and use the compiler to derive a
Generictype class instance.
- A library developer defines a function that can implement an instance for a given type class (e.g.
BoundedEnum, etc.) for all possible types.
- You use the library developer's function to implement your data type's instance for a type class.
Great! So how does it work?
The compiler can define two functions,
to converts your data type (i.e.
MyType) to a new data type (let's say
CompilerRepresentationType for lack of a better name) that has a different structure than your data type but stores the same information.
from converts a value of
CompilerRepresentationType back into a value of
These two functions abide by one law:
(from (to myDataTypeValue)) == myDataTypeValue
The library developer writes a function that can implement an instance for the desired type class (e.g.
BoundedEnum) that works on
CompilerRepresentationType. Generics works by first converting your data type into
CompilerRepresentationType, then uses the library developer's function to implement the instance, and then converts the resulting value of the
CompilerRepresentationType type back into your original type (i.e.
Put visually, read things from left to right as a timeline of events:
MyType --> CompilerRepresentationType ==> CompilerRepresentationType ~~> MyType
--> is where the compiler converts your type into the "same-info, different structure" type via the derived
to function from the
Generic type class
==> is the library developer's function that implements the instance
~~> is where the compiler converts the "same-info, different structure" type back into your type via the derived
from function from the
Generic type class
To understand how the compiler produces
CompilerRepresentationType and how the library developer writes their function, read @hdgarrood's "Making full use of PureScript's Generic type class"