<div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br>
Message: 20<br>
Date: Sat, 04 Sep 2010 03:40:49 -0400<br>
From: wren ng thornton <<a href="mailto:wren@freegeek.org">wren@freegeek.org</a>><br>
Subject: Re: [Haskell-cafe] Restricted type classes<br>
To: Haskell Cafe <<a href="mailto:haskell-cafe@haskell.org">haskell-cafe@haskell.org</a>><br>
Message-ID: <<a href="mailto:4C81F801.606@freegeek.org">4C81F801.606@freegeek.org</a>><br>
Content-Type: text/plain; charset=UTF-8; format=flowed<br>
<br>
On 9/3/10 12:16 AM, Ivan Lazar Miljenovic wrote:<br>
> 2) How far should I go? Should I restrict myself to the<br>
> "data-oriented" classes such as Functor, Traversable, etc. or should I<br>
> try to make restricted versions of Applicative and Monad? Assuming I<br>
> should:<br>
<br>
I'd say you should do as much as seems reasonable. I tend to take things<br>
as far as I can, but that'd end up doing a lot of the same work as<br>
category-extras. For a general collections library, I think it'd make<br>
sense to try to keep things simpler than that if possible. The simpler<br>
it is, the better the uptake will be, so long as it's still complex<br>
enough to capture what it needs to.<br>
<br>
I'd say you should include: Functor, Foldable, Traversable, Pointed,<br>
Applicative, Monad, and Monoid (both additive and multiplicative in<br>
separate classes, as in the monoids package). Those eight make for a<br>
really comprehensive toolkit that does most of the things people<br>
frequently need. Of course, not every collection will have instances for<br>
all of them.<br></blockquote><div><br></div><div>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).</div>
<div><br></div><div>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.</div>
<div><br></div><div>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.</div>
<div><br></div><div>If you're just going to provide stuff we already have, I don't really see the point. </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
> 2c) Should I keep the classes as-is, or should I explicitly put in the<br>
> constraints mentioned in the Typeclassopedia (e.g. make Applicative an<br>
> explicit superclass of Monad, and define return = pure for<br>
> compatability reasons)? If so, should I bring over Pointed, etc. from<br>
> category-extras to round out the set or just stick with classes that<br>
> are already in base?<br>
<br>
If you're defining a new hierarchy, I'd say you should do it correctly, i.e.<br>
<br>
class Functor where fmap<br>
class Functor => Pointed where unit -- or point<br>
class Pointed => Applicative where (<*>) ; (<*) ; (*>)<br>
class Applicative => Monad where (>>=) ; join<br></blockquote><div><br></div><div>Shouldn't it be:</div><div><br></div><div> class Functor where fmap</div><div> class Pointed where point</div>
<div> class (Functor f, Pointed f) => PointedFunctor f where</div><div> class PointedFunctor f => Applicative f where (<*>); --etc.</div><div> class Applicative f => Monad f where (>>=); --etc.</div>
<div><br></div><div>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.</div>
<div><br></div><div>Cheers,</div><div>John</div></div>