Proposal: Applicative => Monad: Call for consensus
Conor McBride
conor at strictlypositive.org
Wed Jan 5 19:00:51 CET 2011
Hi Dave
On 5 Jan 2011, at 17:25, David Menendez wrote:
> On Wed, Jan 5, 2011 at 8:05 AM, Conor McBride
> <conor at strictlypositive.org> wrote:
>>
>> On 5 Jan 2011, at 12:31, Bas van Dijk wrote:
>>
>>> On Wed, Jan 5, 2011 at 1:14 PM, Conor McBride
>>> <conor at strictlypositive.org> wrote:
>>>>
>>>> cabal install she
>>>
>>> I knew about her but not that she supported default superclass
>>> instances.
>>> Nice!
>>
>> She didn't. But she does now.
>
> How does she handle multiple subclasses?
>
> E.g., Functor can be defined in terms of Applicative (fmap = liftA)
> and in terms of Traversable (fmap = liftT). There are plenty of types
> which are both.
She lets you opt out. This is vital to any such default subclass
scheme.
I can write
instance Monad Maybe where
return = Just
Nothing >>= _ = Nothing
Just x >>= f = f x
hiding instance Functor Maybe -- notation renegotiable
and I'll get the Monad and Applicative instances, but not the Functor.
Of course, if I don't otherwise provide a Functor instance, GHC will
complain that it's missing. Crucially, however, I'm not forced to take
the default.
The ability to opt out of the default is crucial for several reasons:
(1) You might have a choice of defaults, e.g. indeed, Functor from
Applicative or Traversable, and you must choose at most one,
even if they are extensionally equal.
(2) You might have inherited a Functor from a library whose author
did not know or care that it was Applicative (because it was
obviously not a Monad, of course). You should not be prevented
from declaring an Applicative instance by the prior Functor
instance.
(3) In the case of monad transformers, I might not want an instance
Monad m => Functor (T m), especially if it prevents me from
defining an instance Functor f => Functor (T f). (cf Oleg's
example.)
Please note that it's the cheapness of opting in, not requiring the
user to assign the methods to their superclasses which assists with
backward compatibility. It's been pointed out to me that one might
consider
class (A x, A y) => B x y where
bthingy = ..
instance A x where
aring = ..
ading = ..
instance A y where
aring = ..
ading = ..
with *two* default A instances. If we were to allow this, we should
need to be able to switch at least one off in some
instance B x x
and, otherwise, to write stuff like
instance B Int Bool where
bthingy = ..
instance A Int where
aring = ..
to be clear which A instance gets the overridden aring. At the
moment, she doesn't handle this terribly well: you can have both
defaults (unmodified) or neither.
It's been helpful thinking about the problem in preprocessor terms,
because it helps to figure out where the controls need to be.
I hope this is progress, anyway.
Cheers
Conor
More information about the Libraries
mailing list