<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 &lt;<a href="mailto:wren@freegeek.org">wren@freegeek.org</a>&gt;<br>
Subject: Re: [Haskell-cafe] Restricted type classes<br>
To: Haskell Cafe &lt;<a href="mailto:haskell-cafe@haskell.org">haskell-cafe@haskell.org</a>&gt;<br>
Message-ID: &lt;<a href="mailto:4C81F801.606@freegeek.org">4C81F801.606@freegeek.org</a>&gt;<br>
Content-Type: text/plain; charset=UTF-8; format=flowed<br>
<br>
On 9/3/10 12:16 AM, Ivan Lazar Miljenovic wrote:<br>
&gt; 2) How far should I go?  Should I restrict myself to the<br>
&gt; &quot;data-oriented&quot; classes such as Functor, Traversable, etc. or should I<br>
&gt; try to make restricted versions of Applicative and Monad?  Assuming I<br>
&gt; should:<br>
<br>
I&#39;d say you should do as much as seems reasonable. I tend to take things<br>
as far as I can, but that&#39;d end up doing a lot of the same work as<br>
category-extras. For a general collections library, I think it&#39;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&#39;s still complex<br>
enough to capture what it needs to.<br>
<br>
I&#39;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&#39;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&#39;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&#39;t just change the imports.  I&#39;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&#39;s this last step of a common map interface, queue interface, etc. that&#39;s missing.</div>
<div><br></div><div>If you&#39;re just going to provide stuff we already have, I don&#39;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>
&gt; 2c) Should I keep the classes as-is, or should I explicitly put in the<br>
&gt; constraints mentioned in the Typeclassopedia (e.g. make Applicative an<br>
&gt; explicit superclass of Monad, and define return = pure for<br>
&gt; compatability reasons)?  If so, should I bring over Pointed, etc. from<br>
&gt; category-extras to round out the set or just stick with classes that<br>
&gt; are already in base?<br>
<br>
If you&#39;re defining a new hierarchy, I&#39;d say you should do it correctly, i.e.<br>
<br>
     class                Functor     where fmap<br>
     class Functor     =&gt; Pointed     where unit -- or point<br>
     class Pointed     =&gt; Applicative where (&lt;*&gt;) ; (&lt;*) ; (*&gt;)<br>
     class Applicative =&gt; Monad       where (&gt;&gt;=) ; join<br></blockquote><div><br></div><div>Shouldn&#39;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) =&gt; PointedFunctor f where</div><div>    class PointedFunctor f =&gt; Applicative f where (&lt;*&gt;); --etc.</div><div>    class Applicative f =&gt; Monad f where (&gt;&gt;=); --etc.</div>
<div><br></div><div>even I might omit PointedFunctor, though, because it doesn&#39;t add anything.  If it is omitted, that just means your Applicative contexts are slightly longer.  But please don&#39;t make Pointed depend on Functor - we&#39;ve already seen that it won&#39;t work for Bloom filters.</div>
<div><br></div><div>Cheers,</div><div>John</div></div>