<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Sep 12, 2013 at 2:37 AM, John Lato <span dir="ltr">&lt;<a href="mailto:jwlato@gmail.com" target="_blank">jwlato@gmail.com</a>&gt;</span> wrote:<br>


<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">I didn&#39;t see this message and replied privately to Michael earlier, so I&#39;m replicating my comments here.<br>


<br></div></blockquote><div><br></div><div>Sorry about that, I wrote to you privately first and then thought this might be a good discussion for the cafe.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


<div dir="ltr"><div>1.  Sooner or later I expect you&#39;ll want something like this:<br><pre><div><span>class</span> <span>LooseMap</span> <span>c</span> <span>el</span> <span>el&#39;</span> <span>where</span></div>

<div>  <span>lMap</span> <span>::</span> <span>(</span><span>el</span> <span>-&gt;</span> <span>el&#39;</span><span>)</span> <span>-&gt;</span> <span>c</span> <span>el</span> <span>-&gt;</span> <span>c</span> <span>el&#39;<br>



</span></div></pre></div><div>
It covers the case of things like hashmaps/unboxed vectors that have 
class constraints on elements.  Although maybe LooseFunctor or LFunctor 
is a better name.<br></div><div><br></div><div>Probably something similar for Traversable would be good also, as would a default instance in terms of Functor.<br>
</div><div><br></div></div></blockquote><div><br></div><div>That&#39;s interesting. It&#39;s quite similar to the CanMap[1] class in classy-prelude or Each from lens, except it can drop a type parameter and the fundeps by requiring the container to be polymorphic. If we&#39;re willing to use more exotic extensions, ConstraintKinds could be useful as well:</div>

<div><br></div><div><div>class ConstrainedMap t where</div><div>    type MapConstraint t e :: Constraint</div><div>    cMap :: (MapConstraint t e1, MapConstraint t e2) =&gt; (e1 -&gt; e2) -&gt; t e1 -&gt; t e2</div><div>
instance ConstrainedMap Set.Set where</div>
<div>    type MapConstraint Set.Set e = Ord e</div><div>    cMap = Set.map</div></div><div><br></div><div>One reason I&#39;d definitely not want to call this anything with the name Functor in it is because Set.map can violate the Functor laws, in particular:</div>

<div><br></div><div>    Set.map (f . g) /= Set.map f . Set.map g</div><div><br></div><div>I believe the only law that could be applied to Set.map would be:</div><div><br></div><div>    Set.map f = Set.fromList . List.map f . Set.toList</div>

<div><br></div><div>I would presume this would generalize to any other possible instance.</div><div><br></div><div>One final idea would be to take your LooseMap and apply the same kind of monomorphic conversion the rest of the library uses:</div>

<div><br></div><div><div>class MonoLooseMap c1 c2 | c1 -&gt; c2, c2 -&gt; c1 where</div><div>    mlMap :: (Element c1 -&gt; Element c2) -&gt; c1 -&gt; c2</div><div>instance (Ord e1, Ord e2) =&gt; MonoLooseMap (Set.Set e1) (Set.Set e2) where</div>

<div>    mlMap = Set.map</div></div><div><br></div><div>Of all of them, ConstrainedMap seems like it would be the most user-friendly, as error messages would just have a single type parameter. But I don&#39;t have any strong leanings.</div>

<div><br></div><div>[1] <a href="http://haddocks.fpcomplete.com/fp/7.4.2/20130829-168/classy-prelude/ClassyPrelude-Classes.html#t:CanMap">http://haddocks.fpcomplete.com/fp/7.4.2/20130829-168/classy-prelude/ClassyPrelude-Classes.html#t:CanMap</a></div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div>
</div><div>2.  IMHO cMapM_ (and related) should be part of the Foldable class.  This is entirely for performance reasons, 
but there&#39;s no downside since you can just provide a default instance.<br>
<br></div></div></blockquote><div><br></div><div>Makes sense to me, done. By the way, this can&#39;t be done for sum/product, because those require a constraint on the Element.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<div dir="ltr"><div></div><div>3.  I&#39;m not entirely sure that the length* functions 
belong here.  I understand why, and I think it&#39;s sensible 
reasoning, and I don&#39;t have a good argument against it, but I just don&#39;t
 like it.  With those, and mapM_-like functions, it seems that the 
foldable class is halfway to being another monolithic ListLike.  But I 
don&#39;t have any better ideas either.<br>
</div><div><br></div></div></blockquote><div><br></div><div>I agree here, but like you said in (2), it&#39;s a performance concern. The distinction I&#39;d make from ListLike is that you only have to define foldr/foldl to get a valid instance (and even that could be dropped to just foldr, except for conflicts with the default signatures extension).</div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div></div>As to the bikeshed color, I would 
prefer to just call the classes Foldable/Traversable.  People can use 
qualified imports to disambiguate when writing instances, and at call 
sites client code would never need Data.{Foldable|Traversable} and can 
just use these versions instead.  I&#39;d still want a separate name for 
Functor though, since it&#39;s in the Prelude, so maybe it&#39;s better to be 
consistent.  My $.02.<br></div><div><div><div class="gmail_extra"><br></div></div></div></blockquote><div><br></div><div>I prefer avoiding the name conflict, for a few reasons:</div><div><div><ul><li>In something like ClassyPrelude, we can export both typeclasses without a proper if they have separate names.</li>

<li>Error messages and documentation will be clearer. Consider how the type signature `ByteString -&gt; foo` doesn&#39;t let you know whether it&#39;s a strict or lazy bytestring.</li><li>I got specific feedback from Edward that it would be easier to include instances for these classes if the names didn&#39;t clash with standard terminology.</li>

<li>It leaves the door open for including this concept upstream in the future, even if that&#39;s not the goal for now.</li></ul></div></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<div><div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Sep 11, 2013 at 3:25 PM, Michael Snoyman <span dir="ltr">&lt;<a href="mailto:michael@snoyman.com" target="_blank">michael@snoyman.com</a>&gt;</span> wrote:<br>



<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">That&#39;s really funny timing. I started work on a very similar project just this week:<div>

<br></div>
<div>
<a href="https://github.com/snoyberg/mono-traversable" target="_blank">https://github.com/snoyberg/mono-traversable</a><br>


</div><div><br></div><div>It&#39;s not refined yet, which is why I haven&#39;t discussed it too publicly, but it&#39;s probably at the point where some review would make sense. There&#39;s been a bit of a discussion on a separate Github issue[1] about it.</div>






<div><br></div><div>A few caveats:</div><div><ul><li>The names are completely up for debate, many of them could be improved.<br></li><li>The laws aren&#39;t documented yet, but they mirror the laws for the polymorphic classes these classes are based on.</li>





<li>The Data.MonoTraversable module is the main module to look at. The other two are far more nascent (though I&#39;d definitely appreciate feedback people have on them).</li></ul><div>I think this and mono-foldable have a lot of overlap, I&#39;d be interested to hear what you think in particular John.</div>





</div><div><br></div><div>Michael</div><div><br></div><div>[1] <a href="https://github.com/snoyberg/classy-prelude/issues/18" target="_blank">https://github.com/snoyberg/classy-prelude/issues/18</a></div>
<div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Sep 11, 2013 at 11:05 PM, John Lato <span dir="ltr">&lt;<a href="mailto:jwlato@gmail.com" target="_blank">jwlato@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">





<div dir="ltr"><div><div>I agree with everything Edward has said already.  I went through a 
similar chain of reasoning a few years ago when I started using 
ListLike, which provides a FoldableLL class (although it uses fundeps as
 ListLike predates type families).  ByteString can&#39;t be a Foldable instance, nor do I think most people would want it to be.<br><br></div><div>Even though I would also like to see mapM_ in bytestring, it&#39;s probably faster to have a library with a separate monomorphic Foldable class.  So I just wrote one:<br>






<br><a href="https://github.com/JohnLato/mono-foldable" target="_blank">https://github.com/JohnLato/mono-foldable</a><br><a href="http://hackage.haskell.org/package/mono-foldable" target="_blank">http://hackage.haskell.org/package/mono-foldable</a><br>





</div>
<div><br></div>Petr Pudlak has done some work in this area.  A big problem is that foldM/mapM_ are typically implemented in terms of Foldable.foldr (or FoldableLL), but this isn&#39;t always optimal for performance.  They really need to be part of the type class so that different container types can have specialized implementations.  I did that in mono-foldable, using Artyom&#39;s map implementation (Artyom, please let me know if you object to this!)<br>






<br></div><div>pull requests, forks, etc all welcome.<br></div><div><br></div><div>John L.<br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote"><div><div>On Wed, Sep 11, 2013 at 1:29 PM, Edward Kmett <span dir="ltr">&lt;<a href="mailto:ekmett@gmail.com" target="_blank">ekmett@gmail.com</a>&gt;</span> wrote:<br>






</div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div><div dir="ltr">mapM_ is actually implemented in terms of Foldable, not Traversable, and its implementation in terms of folding a ByteString is actually rather slow in my experience doing so inside lens and isn&#39;t much faster than the naive version that was suggested at the start of this discussion.<div>







<br></div><div>But as we&#39;re not monomorphizing Foldable/Traversable, this isn&#39;t a think that is able to happen anyways.<span><font color="#888888"><br><div><br></div><div>-Edward</div></font></span></div>
</div><div><div><div class="gmail_extra"><br><br><div class="gmail_quote">
On Wed, Sep 11, 2013 at 2:25 PM, Henning Thielemann <span dir="ltr">&lt;<a href="mailto:lemming@henning-thielemann.de" target="_blank">lemming@henning-thielemann.de</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">







<div><br>
On Wed, 11 Sep 2013, Duncan Coutts wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
For mapM etc, personally I think a better solution would be if<br>
ByteString and Text and other specialised containers could be an<br>
instance of Foldable/Traversable. Those classes define mapM etc but<br>
currently they only work for containers that are polymorphic in their<br>
elements, so all specialised containers are excluded. I&#39;m sure there<br>
must be a solution to that (I&#39;d guess with type families) and that would<br>
be much nicer than adding mapM etc to bytestring itself. We would then<br>
just provide efficient instances for Foldable/Traversable.<br>
</blockquote>
<br></div>
I&#39;d prefer to keep bytestring simple with respect to the number of type extensions. Since you must implement ByteString.mapM anyway, you can plug this into an instance definition of Traversable ByteString.<br>
</blockquote></div><br></div>
</div></div><br></div></div><div>_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/libraries" target="_blank">http://www.haskell.org/mailman/listinfo/libraries</a><br>
<br></div></blockquote></div><br></div>
<br>_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/libraries" target="_blank">http://www.haskell.org/mailman/listinfo/libraries</a><br>
<br></blockquote></div><br></div></div>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div></div>