On 9/4/10 3:50 AM, Ivan Lazar Miljenovic wrote:
On 4 September 2010 17:40, wren ng thornton<w...@freegeek.org>  wrote:
So, in the interest of generality, perhaps you should just pick a letter or
a short prefix and use that for each of the classes. In my blog posts I
called them 0-monads, 1-monads, and 2-monads; following Ganesh Sittampalam
and Matthieu Sozeau, they'd be monads, r-monads, and g-monads.

I think I'd prefer to put the prefix on the kind * versions (though
does a kind * version of something like Monad even make sense?).

Oh sure. I was just meaning that you should do something systematic like have XFoo and YFoo, instead of having Foo and Bar. That way people can just remember ({X,Y},{Foo,Fob,Fez}) instead of having to remember {(Foo,Bar), (Fob,Baz), (Fez,Quux)}.

I'm a fan of keeping the undecorated names for the current versions, and using a prefix for the * versions.

I'd say you should include: Functor, Foldable, Traversable, Pointed,
Applicative, Monad, and Monoid (both additive and multiplicative in separate
classes, as in the monoids package). Those eight make for a really
comprehensive toolkit that does most of the things people frequently need.
Of course, not every collection will have instances for all of them.

Monoid was probably just going to be re-exported from base, since it's
already for kind * (and as such works with all types, and doens't need
any parametricity).

I was just talking general API, not necessarily what you need to write. Reusing the standard classes is fine.

Well, the point was that liftA/liftA2 might make more sense as being
the methods to be defined for some types rather than<*>, but you
could define them in terms of each other.

Well, liftA and liftM are just generic implementations of fmap using pure/(<*>) and return/(>>=). If you can define fmap directly, then you should do so. If you can't, you're always free to use the implementations that liftA and liftM use. The liftA function is defined explicitly for allowing you can say """instance Functor F where fmap = liftA""". There's no reason for liftA to belong to Applicative, because it has Functor as a superclass and therefore fmap exists. Since fmap can be more efficient than liftA, it is better to use fmap when writing code. Note that (<$>) is defined as fmap, and liftA2, liftA3, etc are defined in terms of (<$>) i.e. fmap.

For liftM things are a bit hazier because Monad fails to mention Functor as an explicit superclass, but it really ought to. Assuming it did, then there's no reason for liftM to belong to Monad, because we're assured that fmap exists. Though, again, liftM should be defined as a non-class function in order to serve as a default implementation of fmap for those who need it. This is the same reason why Data.Traversable defines fmapDefault and foldMapDefault: not so that they can be used as functions, but so that they can be used for giving class instances. Perhaps we should be calling them fmapApplictiveDefault, fmapMonadDefault, and fmapTraversableDefault instead...

I suppose you could use liftA2 as the basis of Applicative instead of (<*>), but that seems a bit perverse to me. The (<*>) operation captures exactly what we want to say--- namely the K axiom for modal logics; which is equivalent to saying the applicative category has exponentials; which is also the name for the whitespace of function application;... . Whereas liftA2 seems like a far more round-about way of getting there. There may be efficiency reasons for arguing that liftA2 should be included in _addition_ to (<*>), but I'm not aware of them.

--
Live well,
~wren
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to