
On Mon, Sep 6, 2010 at 5:11 PM, John Lato
Message: 20 Date: Sat, 04 Sep 2010 03:40:49 -0400 From: wren ng thornton
Subject: Re: [Haskell-cafe] Restricted type classes To: Haskell Cafe Message-ID: <4C81F801.606@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@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Work is punishment for failing to procrastinate effectively.