Comparing class alias proposals
John Meacham's proposal for type class aliases has been around for a few years now. It has not been implemented yet; instead, several variations to his original proposal have come up. In this document we collect those ideas and their motivations in a hopefully clear overview. We also point out potential pitfalls or things that need more pondering: many ideas look very attractive and promising but prove troublesome when made formal. We believe this is the main reason they haven't been implemented yet.
For each idea we give a motivation from the point of view of a stakeholder. We identify three stakeholders:
- the designer of a class or class hierarchy;
- the author of class instances;
- the programmer using the classes and instances.
Furthermore, most motivations can be grouped into two categories:
- increasing the flexibility of the class system, useful when designing new API;
- changing an existing API while maintaining backwards compatibility.
1 List of proposals
We've found the following documents that propose extensions or variations of the original proposal:
- John Meacham's original proposal
- Context alias
- Superclass defaults
- Class system extension proposal
- GHC ticket 788: Class aliases
2 Context synonyms
The most basic idea is that of a context synonym (CS):
context BoundedEnum a = (Bounded a, Enum a) context SatisfyA f s = (Satisfy f, Alternative f, Input f ~ s)
A context synonym may appear anywhere a context is allowed:
- in the type signature of a function;
- in a data type or constructor;
- in a superclass constraint.
The arguments to a CS have to be kind-checked. In the examples above:
Bounded, Enum, BoundedEnum :: * -> Context Satisfy, Alternative :: (* -> *) -> Context Input :: (* -> *) -> * SatisfyA :: (* -> *) -> * -> Context
Context synonyms are synonymous and interchangable with their right-hand sides, much like type synonyms. Specifically, they do not define any new classes (dictionaries) or functions. Ideally, they can be exported and documented, just like type synonyms.
Motivation: CS's are useful when a particularly long context keeps popping up, something that often happens when type-level programming is applied, for example with generic programming. They are interesting for programmers using already existing classes.
3 Higher-order context synonyms
Possible additions to the context synonyms include:
May a CS's RHS refer to other CS's? For example:
context Foo a = (BoundedEnum a, Eq a, Ord a)
This introduces the possibility of loops. Should loops be forbidden? It could be argued that in some cases of loops, the CS's transitive closure should be used, but this is only acceptable if the closure is finite. It seems more elegant to just forbid all loops.
Apart from type constructors, may a CS's variables be class constructors (things of kind ... -> Context) as well? For example:
context Bar a = a Int
Here Bar :: (* -> Context) -> Context
May CS's be passed as arguments to other CS's? For example:
context Biz = Bar BoundedEnum
May CS's be partially applied? Consider these alternate definitions of BoundedEnum:
context BoundedEnum a = (Bounded, Enum) a context BoundedEnum = (Bounded, Enum)
This would overload the
, separator to accept not just things of kind * as operands, but things of any kind, as long as the kinds of both operands are equal.
Motivation: these ideas are direct extensions of context synonyms and are useful for clients.