[Haskell-cafe] Functor => Applicative => Monad

mokus at deepbondi.net mokus at deepbondi.net
Thu Dec 23 16:13:13 CET 2010

On 22/12/2010 19:03, Simon Marlow wrote:
> On 14/12/2010 08:35, Isaac Dupree wrote:
>> On 12/14/10 03:13, John Smith wrote:
>>> I would like to formally propose that Monad become a subclass of
>>> Applicative, with a call for consensus by 1 February. The change is
>>> described on the wiki at
>>> http://haskell.org/haskellwiki/Functor-Applicative-Monad_Proposal,
>> That page isn't written as a proposal yet, it's written as a bunch of
>> ideas. I would be happy to see something along the lines of Bas van
>> Dijk's work
>> http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/14740 .
> This is a proposal with far-reaching consequences, and with several
> alternative designs. I'm not sure I understand all
> the tradeoffs. Some parts of the proposal are orthogonal to the rest
> (e.g. changing fmap to map), and should probably be
> considered separately.
> Could someone please write a detailed proposal, enumerating all the
> pros and cons, and the rationale for this design
> compared to other designs?
> Cheers,
> Simon

I don't know exactly what the proposal process is, but what I'd like to
see is something like the following:

1)	"Subclasses" may declare default implementations of inherited methods. 
For example:

> 	class Functor f => Applicative f where
> 		...
>		fmap f x = pure f <*> x
>	class Applicative f => Monad f where
>		...
>		pure = return
>		(<*>) = ap

2)	Unless superclass instances are already in scope at declaration of an
instance,  an instance declaration implicitly also declares the superclass
(and may also explicitly define functions in the superclass).  For

>	instance Monad Maybe where
>		return = Just
>		(>>=) = ...
>		fmap = ...

This declaration, in the absence of any explicit "instance Functor Maybe"
and "instance Applicative Maybe", would implicitly define those instances
as well, with the default implementations of fmap, pure, and <*> given.

It would be a compile-time error to inherit multiple default definitions
of a method, unless:
	a) There is a clear "shadowing" (eg, if the Monad class declaration
included a default fmap, that would take precedence over the one in
	b) The instance declaration explicitly defines the function, thus
resolving the conflict.

These changes, I believe, would make it possible to restructure the
heirarchy with negligible impact on user code.  The only potential impact
I see so far would have to involve orphan instances, which are already
considered risky/not a good idea.  Specifically, if there were already an
orphan Monad instance in one place and an orphan Applicative instance in
another, the orphaned Applicative instance would become a duplicate
instance which could potentially bite an end-user importing both modules.

It would also be possible with fairly small user impact to move 'return'
to Applicative, or even to a new 'Pointed' superclass of Applicative.  To
the end user, the type 'return :: Monad m => a -> m a' would still be
valid, as would including "return" in a Monad instance declaration. 
Including 'pure' as well in Applicative (with defaults pure = return,
return = pure) would allow old Applicative declarations to continue to
work unchanged as well,  though that obviously has the downside of
introducing a new recursive default which is always potentially confusing
to writers of new instances.

	-- James

PS. Incidentally, I'd also prefer a class like the following instead of
Applicative as it is now:
>	class Functor f => Monoidal f where
>		return :: a -> f a
>		(<*>)  :: f a -> f b -> f (a,b)

But that would be a much more disruptive change.

More information about the Haskell-Cafe mailing list