I’m a little bit concerned about the direction we’re taking with respect to class and instance declarations. It is mainly about readability and intention of the code. Let me first summarise two current issues and state my concerns, after which I’ll introduce a possible way to ease the pain.
Kind annotations and class inheritance
First, since PureScript 0.14, we can add kind annotations to datatypes, newtypes and classes.
When browsing some source code, I stumbled upon this (there are more examples):
class Category :: forall k. (k -> k -> Type) -> Constraint
class Semigroupoid a <= Category a where
identity :: forall t. a t t
I don’t know if I’m alone in this, but reading this code from top to bottom boggles my mind. It goes like this:
- “Ah, we’re declaring a
Categoryclass.” - “Oh wait! It’s the
Semigroupoidclass!” - “Oh sorry.
Semigroupoidis the superclass of theCategoryclass.”
I know, writing down the superclass before the new class is the way we always did it,
is the way Haskell does it for some decades, but…
- Now that we have kind annotations, they don’t align with the declaration.
- It makes me wonder what we are declaring here.
- It remembers me of reading C, where type annatations read backwards.
Instance declarations and forall
Second, a PR has been merged which removes of explicit instance names. The compiler can generate them. Wonderful! We’re also discussion the addition of forall to instance declarations, which helps avoiding problems with type variable scoping. Hurray! I guess the end result will be something like this:
instance forall a b. (Show a, Show b) => Show (Tuple a b) where ...
Some observations:
-
We’re repeating ourselves. We have to state that we’re declaring an instance for all
aandb, but the part after the=>implicitly states the same thing. -
Just as with class declarations, it reads backwards. We’re declaring an instance of
ShowonTuples, and for that we need two otherShowconstraints. (But again, we did this, and Haskell did this, for decades now…) -
The introduction of an explicit
forallfor instances, also raises the question: Shouldn’t we treat class declarations the same and add an explicitforallthere too to aid type variable scoping?class Category :: forall k. (k -> k -> Type) -> Constraint class forall a. Semigroupoid a <= Category a where ...
Consistency with type and data declarations
For type and data declarations we do not need an explicit forall, as the type variables are introduced together with the data declaration. When, for example, we write data Tuple a b = ..., it is clear that we are introducing type variables a and b, and we’re only allowed to use a and b after the equals sign. We don’t have to repeat ourselves! Why shouldn’t we do the same thing with class and instance declarations?
So, what if we make the experience of entity declaration simpler and more uniform by starting every declaration with the name we are declaring, together with the variables that can be used in that declaration.
So:
-
typeanddatadeclarations stay untouched; -
classdeclarations start with the class we’re declaring together with their type variables, followed by their superclasses which can use the type variables introduced earlier
(as is custom in I think every language with some kind of oo-class or interface/protocol/trait inheritance except Haskell and Idris); - do the same for
instancedeclarations; - drop the explicit
forall.
data Tuple a b = ...
type Usually a = ...
class Category :: forall k. (k -> k -> Type) -> Constraint
class Category a | Semigroupoid a where ...
instance Show (Tuple a b) | Show a, Show b where ...
I’m curious if other people’s minds have to do the same yoga when reading current class and instance declarations, and if above proposal would enhance DX.
I find that a real good counter argument for my issues with instance declarations. That only leaves the class case.
I think separating function definitions from their type annotations on functions is one of the great appeals of Haskell-like syntax. For me, the same holds for type/data/class declarations and their kind annotations.
A nice read! Thanks to