[Haskell-cafe] Restricted type classes

Ivan Lazar Miljenovic ivan.miljenovic at gmail.com
Sat Sep 4 03:50:36 EDT 2010


On 4 September 2010 17:40, wren ng thornton <wren at freegeek.org> wrote:
> On 9/3/10 12:16 AM, Ivan Lazar Miljenovic wrote:
>>
>> 1) How should I name the kind * versions?  For example, the kind *
>> version of Functor is currently called Mappable with a class method of
>> rigidMap.  What should I call the kind * version of Foldable and its
>> corresponding methods?  Is there a valid system I can use for these?
>
> I think it'd be good to be consistent, whatever you do. For (*->*->*) monads
> I've seen them called GMonads (for "generalized") and indexed monads. For
> the (*->*) monads, I've seen RMonads and parameterized monads. Here are some
> links for those who may be interested; they have more links to independent
> invention by Oleg Kiselyov and also by Bob Atkey, as well as a Coq
> implementation and a mention of Agda. (For my part, I've since moved on to
> playing with monads between different categories, which isn't really germane
> here.)
>
>    http://winterkoninkje.dreamwidth.org/65416.html
>    http://winterkoninkje.dreamwidth.org/65585.html
>
> 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?).

>> 2) How far should I go?  Should I restrict myself to the
>> "data-oriented" classes such as Functor, Traversable, etc. or should I
>> try to make restricted versions of Applicative and Monad?  Assuming I
>> should:
>
> I'd say you should do as much as seems reasonable. I tend to take things as
> far as I can, but that'd end up doing a lot of the same work as
> category-extras. For a general collections library, I think it'd make sense
> to try to keep things simpler than that if possible. The simpler it is, the
> better the uptake will be, so long as it's still complex enough to capture
> what it needs to.
>
> 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).

>> 2b) Is it OK to promote functions that use a class to being class
>> methods?  When I was discussing this in #haskell several people
>> mentioned that defining something like liftA2 for the Set instance of
>> (restricted) Applicative would make more sense than the default<*>
>> (since (a ->  b) isnt' an instance of Ord).
>
> That depends. In general, it's better to have smaller classes because it
> reduces the burden on programmers writing instances and it allows for
> smaller dictionaries at runtime. In general, I'd say that functions should
> be included into the class when they often permit specialized definitions
> which are more efficient than the generic one. And of course, they should be
> included when they serve as the basis of the class (e.g., both (==) and (/=)
> should be included in Eq since they both serve as a basis for equality, with
> no one being obviously easier to implement than the other). If there's
> little chance of a performance gain, then why would you want it in the class
> at all?

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.

>> 2c) Should I keep the classes as-is, or should I explicitly put in the
>> constraints mentioned in the Typeclassopedia (e.g. make Applicative an
>> explicit superclass of Monad, and define return = pure for
>> compatability reasons)?  If so, should I bring over Pointed, etc. from
>> category-extras to round out the set or just stick with classes that
>> are already in base?
>
> If you're defining a new hierarchy, I'd say you should do it correctly, i.e.
>
>    class                Functor     where fmap
>    class Functor     => Pointed     where unit -- or point
>    class Pointed     => Applicative where (<*>) ; (<*) ; (*>)
>    class Applicative => Monad       where (>>=) ; join
>
> There's no benefit to preserving the ill designs of the past.

Yes, that was my point.

>> 3) Am I wasting my time with this?
>
> Not at all. Many people want a good containers API, and many people want a
> cleaned up version of the categorical classes which isn't quite as involved
> as category-extras. Go for it!

*sigh* I was almost wishing people would say I _was_ wasting my time
with this... ;-)
-- 
Ivan Lazar Miljenovic
Ivan.Miljenovic at gmail.com
IvanMiljenovic.wordpress.com


More information about the Haskell-Cafe mailing list