[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
>> 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?
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.
> 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.
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