This article is mainly an overview and doesn’t try to explain each type class. I also want to point out some opinionated critique.
The Typeclassopedia explains a few more type classes.
Pointed is a superclass of
Applicative with just
I am not against this separation, but can’t think of an example of
Pointed, that isn’t also
MonadFix is not as well known as some other type classes, but is actually quite useful.
RecursiveDo extension adds some syntactic sugar to
This allows recursive bindings in do-notation.
I am only covering the “left” side of the Typeclassopedia.
To conclude the Typeclassopedia, let’s look at
Alternative is a monoid
Alternative can actually be expressed with the other already introduced type classes.
class (Applicative f, forall x. Monoid (f x)) => Alternative f where empty :: f a empty = mempty (<|>) :: f a -> f a -> f a (<|>) = (<>)
The only problem is, that base introduces some
Monoid instances, that don’t work with this definition.
Maybe for example uses a superclass constraint.
class Semigroup a => Monoid (Maybe a) where -- ...
Alternative doesn’t work, because
forall a. Semigroup a (from
Maybe) is a stronger constraint than
forall x. (from
I am not quite sure, whether this change can actually break
Maybe example will be caught by the compiler at least.
The solution would be to use compatible instances.
The currently used instances can still be made available with
The current situation isn’t bad though, considering that
newtypes are annoying to use.
Maybe idris made the right choice with named implementations (multiple named instances in Haskell terms).
Another interesting change would be the separation of
empty, similar to the separation of
The structure of
Let’s start with
This type class was a stupid idea to allow pattern matching in do-notation.
Whenever writing actual code you should use a case-block.
Patterns that always match are fine, but other patterns should just give a warning like “patterns are non-exhaustive”.
Bitraversable are nice to have.
Quadrofunctor, etc. are missing though.
I’m not sure how those type classes would be implemented without boilerplate.
MonadIO is a type class for all monads, that use
IO as the base monad.
This is a useful type class, but it can be completely replaced with
MonadBase from transformers-base.
MonadBaseControl from monad-control could be added to base.
I am in favor of completely removing
Alternative, the contravariant library defines
These two type class can be quite useful, but I haven’t explored this direction any further.
Monoidwill often have multiple lawful instances, but Haskell requires us to use a
newtypefor each implementation. Instances should be chosen wisely.
Applicativecan be thought of as monoids.
MonadFailis a fail.
MonadTransControlwould be a nice addition to base, including
Other type classes like
IsListor other stock classes deserve their own discussion.