Functor hierarchy proposal and class system extension proposal

Conor McBride conor at
Tue Jan 4 14:21:32 CET 2011


On 2 Jan 2011, at 09:29, Malcolm Wallace wrote:

> See also

A proposal from Jón Fairbairn for how to add default superclass method
definitions gained some traction, and deserves to be revi(v/s)ed now, I

Some superclass relationships are `shallow' interface extensions:  
does not give you a standard way to implement Monad, just more  
within a monad. Other superclass relationships `deepen' existing
functionality---if you have Ord, you can certainly make Eq; if you have
Monad, you can certainly make Applicative, etc. The former is currently
well supported, the latter badly.

Jón's proposal was to improve the latter situation by allowing the  
to specify a default (partial) implementation of a superclass. So we  

   class Applicative f where
     return :: x -> f x
     (<*>) :: f (s -> t) -> f s -> f t
     instance Functor f where
       fmap = pure . (<*>)

giving not only a subclass constraint (Functor f =>) but also a standard
means to satisfy it. Whenever an Applicative instance is declared, its
Functor sub-instance is unpacked: buy one, get one free.

This, on its own, is not quite enough. For one thing, we need a way to
switch it off. I should certainly be permitted to write something like

   instance Applicative Blah where
     return = ...
     (<*>) = ...
     hiding instance Functor Blah

to prevent the automatic generation of the superclass instance. The
subclass constraint would still apply, so in order to use the  
functionality of Blah, it would have to be a Functor otherwise, e.g., by
being Traversable. This `hiding' option was missing from Jón's proposal,
but it seems crucial to address the potential for conflicts which was
identified in the discussion at the time.

It's also clear that we must be able to override the default behaviour.
When the class declaration has a superclass instance, but not otherwise,
a subclass instance should be entitled to override and extend the  
of the superclass instance thus generated. It seems unambiguous to allow
this to happen without repeating the "instance Mutter Something". So
we'd have

   class Monad f where
     (>>=) :: f s -> (s -> f t) -> f t
     instance Applicative f where
       ff <*> fs = ff >>= \ f -> fs >>= \ s -> return (f s)

and we'd still be able to write

   instance Monad Maybe where
     return = Just              -- completing the generated Applicative
     Just s  >>= f = f s
     Nothing >>= _ = Nothing

and acquire Monad, Applicative, Functor.

No new instance inference semantics is required. In order to transform
code under this proposal to code acceptable now, one need only keep
track of which methods belong to which class and which classes have
default superclass instances: each compound instance can then be
split into its individual components before compilation under the
current rules.

Is this clear? Does it seem plausible?

All the best


More information about the Haskell-prime mailing list