
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 example:
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 Applicative) 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.