[Haskell-cafe] Restricted type classes
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,
>> 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.
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
*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
Work is punishment for failing to procrastinate effectively.
More information about the Haskell-Cafe