Mathematical concepts such as monads, functors, monoids, and semigroups are expressed in Haskell as typeclasses. Therefore, in order to exploit relations such as “every monad is a functor”, and “every monoid is a semigroup”, we need to be able to also express relations between typeclasses.
Currently, the only way to do so is using
superclasses
. However, superclasses can be problematic due to their closed nature. Adding a superclass implies modifying the subclass’ definition, which is either impossible if one does not own such code, or painful as it requires cascading changes and the introduction of boilerplate throughout the codebase.
In this article, we introduce
class morphisms
, a way to relate classes in an open fashion, without changing class definitions. We show how class morphisms improve the expressivity, conciseness, and maintainability of code. Further, we show how to implement them while maintaining canonicity and coherence, two key properties of the Haskell type system. Extending a typechecker with class morphisms amounts to adding an elaboration phase and is an unintrusive change. We back this claim with a prototype extension of GHC.
[1]
Matthieu Sozeau,et al.
First-Class Type Classes
,
2008,
TPHOLs.
[2]
Andres Löh,et al.
Deriving via: or, how to turn hand-written instances into an anti-pattern
,
2018,
Haskell@ICFP.
[3]
Meng Wang,et al.
Modular generic programming with extensible superclasses
,
2006,
WGP '06.
[4]
Mark P. Jones,et al.
Instance chains: type class programming without overlapping instances
,
2010,
ICFP '10.
[5]
Mauro Jaskelioff,et al.
Improving typeclass relations by being open
,
2018,
Haskell@ICFP.
[6]
Philip Wadler,et al.
How to make ad-hoc polymorphism less ad hoc
,
1989,
POPL '89.
[7]
Dominique Devriese,et al.
On the bright side of type classes: instance arguments in Agda
,
2011,
ICFP '11.