[Haskell-cafe] Restricted type classes

Gábor Lehel illissius at gmail.com
Mon Sep 6 11:50:06 EDT 2010

On Mon, Sep 6, 2010 at 5:11 PM, John Lato <jwlato at gmail.com> wrote:
>> Message: 20
>> Date: Sat, 04 Sep 2010 03:40:49 -0400
>> From: wren ng thornton <wren at freegeek.org>
>> Subject: Re: [Haskell-cafe] Restricted type classes
>> To: Haskell Cafe <haskell-cafe at haskell.org>
>> Message-ID: <4C81F801.606 at freegeek.org>
>> Content-Type: text/plain; charset=UTF-8; format=flowed
>> On 9/3/10 12:16 AM, Ivan Lazar Miljenovic wrote:
>> > 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.
> Although I agree these do most things that people need, it's very rare that
> I need a data structure that guarantees *only* these features.  Most often I
> need a map, a queue, etc. because I need either lookup by key, queue
> properties, etc.  I think it's necessary to include classes like Indexable
> and Queue.  Indexable may need to be split into two, one for ordered-Int
> indexes (i.e. lists) and one for Maps.  Just a few days ago I wanted to
> change the priority queue implementation in some code.  This was painful
> because the different available implementations all have varying APIs, so I
> couldn't just change the imports.  I've wanted to do this in other contexts
> as well (e.g. maps and tries).
> The perhaps more important use is for coding algorithms that depend upon map
> properties, queue properties, etc., but leaving the actual implementation
> polymorphic so it can be chosen by a higher level.
> If the purpose of this project is to present a common interface for
> containers, then I think you should start by seeing what are the most common
> containers (I would guess lists, sets, maps, and queues) with a goal of
> providing their specific functionality through classes.  Then all the common
> stuff can be stripped out and provided by superclasses.  Of course we
> already know a great deal of the common operations, e.g. Traversable and
> Foldable, and we make use of those abstractions.  It's this last step of a
> common map interface, queue interface, etc. that's missing.
> If you're just going to provide stuff we already have, I don't really see
> the point.
>> > 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
> Shouldn't it be:
>     class Functor where fmap
>     class Pointed where point
>     class (Functor f, Pointed f) => PointedFunctor f where
>     class PointedFunctor f => Applicative f where (<*>); --etc.
>     class Applicative f => Monad f where (>>=); --etc.
> even I might omit PointedFunctor, though, because it doesn't add anything.
>  If it is omitted, that just means your Applicative contexts are slightly
> longer.  But please don't make Pointed depend on Functor - we've already
> seen that it won't work for Bloom filters.
> Cheers,
> John

I think most people have been using "Pointed" merely as shorthand for
"Pointed Functor" -- in the same way that Applicative isn't called
ApplicativeFunctor, even though that's what it is. So if it doesn't
work for Bloom filters, the reason is that Bloom filters aren't
pointed functors.

*That said*, I actually have nothing at all against splitting the 'a
-> f a' method out into a separate class if you think it's useful,
whether you call it Pointed or something else. (And `class (Pointed f,
Functor f) => PointedFunctor f` is sort of cute.) I'm just trying to
clarify where people are probably coming from -- those people can
hopefully correct me if I'm wrong about this.

> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

Work is punishment for failing to procrastinate effectively.

More information about the Haskell-Cafe mailing list