I'm delighted to see these interfaces being explored.  Question: why separate fan-out (&&&) from pair?  Do you know of type constructors that have fst & snd but not &&&?  Similarly for CategoryAssoc.   - Conal
<br><br><div><span class="gmail_quote">On 10/21/07, <b class="gmail_sendername">Twan van Laarhoven</b> &lt;<a href="mailto:twanvl@gmail.com">twanvl@gmail.com</a>&gt; wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Ashley Yakeley wrote:<br>&gt; 3. There might be another useful class that&#39;s a subclass of Category and<br>&gt; a superclass of Arrow, that essentially includes first but not arr. If<br>&gt; someone wants to name it and define it, we can put it in the class
<br>&gt; hierarchy.<br><br><br>My proposal would be the following. The important things are that:<br>&nbsp;&nbsp;1. It incorporates Conal&#39;s deep arrow,<br>&nbsp;&nbsp;2. as well as everything that is needed for functional<br>references/lenses and bijective/invertible functions.
<br>I have chosen to reuse prelude names where possible.<br><br><br>class Category cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;:: cat a a<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.) :: cat b c -&gt; cat a b -&gt; cat a c<br><br><br>-- | &#39;cat&#39; can work with pairs<br>
class Category cat =&gt; CategoryPair cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fst&nbsp;&nbsp;&nbsp;&nbsp;:: cat (a,b) a<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snd&nbsp;&nbsp;&nbsp;&nbsp;:: cat (a,b) b<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;swap&nbsp;&nbsp; :: cat (a,b) (b,a)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first&nbsp;&nbsp;:: cat a b -&gt; cat (a,c) (b,c)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;second :: cat a b -&gt; cat (c,a) (c,b)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(***)&nbsp;&nbsp;:: cat a b -&gt; cat c d -&gt; cat (a,c) (b,d)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snd = fst . swap<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;second f = swap . first f . swap<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f *** g = second g . first f<br><br>class CategoryPair cat =&gt; CategoryFanOut cat where
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&amp;&amp;&amp;) :: cat a b -&gt; cat a c -&gt; cat a (b,c)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dup&nbsp;&nbsp; :: cat a (a,a)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f &amp;&amp;&amp; g = f *** g . dup<br><br><br>-- | &#39;cat&#39; can work with eithers<br>--&nbsp;&nbsp; Dual to CategoryPair
<br>class Category cat =&gt; CategoryChoice cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inl&nbsp;&nbsp;&nbsp;&nbsp;:: cat a (Either a b)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inr&nbsp;&nbsp;&nbsp;&nbsp;:: cat b (Either a b)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mirror :: cat (Either a b) (Either b a)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;left&nbsp;&nbsp; :: cat a b -&gt; cat (Either a c) (Either b c)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;right&nbsp;&nbsp;:: cat a b -&gt; cat (Either c a) (Either c b)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+++)&nbsp;&nbsp;:: cat a b -&gt; cat c d -&gt; cat (a,c) (b,d)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inr = mirror . inl<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;right f = mirror . left f . mirror<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f +++ g = right g . left f
<br><br>class CategoryChoice cat =&gt; CategoryFanIn cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(|||) :: cat a c -&gt; cat b c -&gt; cat (Either a b) c<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;untag :: cat (Either a a) a<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f ||| g = untag . f +++ g<br><br><br>class Category cat =&gt; CategoryZero cat where
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zeroCat :: cat a b<br><br>class CategoryZero cat =&gt; CategoryPlus cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;+&gt;) :: cat a b -&gt; cat a b -&gt; cat a b<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- this is what ArrowPlus uses, but perhaps<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- (///) is a better choice, because it looks more like the others.
<br><br><br>class CategoryPair cat =&gt; CategoryApply cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; app :: cat (cat a b, a) b<br><br><br>class CategoryPair cat =&gt; CategoryLoop cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loop :: cat (a,c) (b,c) -&gt; cat a b<br><br>-- no idea how useful this is, but it is nice for symmetry
<br>class CategoryChoice cat =&gt; CategoryCoLoop cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; coloop :: cat (Either a c) (Either b c) -&gt; cat a b<br><br><br>-- | Categories that can manipulate functions.<br>--&nbsp;&nbsp; This is most of &#39;DeepArrow&#39;.
<br>class Category cat =&gt; CategoryFun cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;&nbsp;:: cat b c -&gt; cat (a -&gt; b) (a -&gt; c)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curry&nbsp;&nbsp; :: cat ((a, b) -&gt; c) (a -&gt; b -&gt; c)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uncurry :: cat (a -&gt; b -&gt; c) ((a, b) -&gt; c)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funF&nbsp;&nbsp;&nbsp;&nbsp;:: cat (c -&gt; a, b) (c -&gt; (a, b))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funS&nbsp;&nbsp;&nbsp;&nbsp;:: cat (a, c -&gt; b) (c -&gt; (a, b))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funR&nbsp;&nbsp;&nbsp;&nbsp;:: cat (a -&gt; c -&gt; b) (c -&gt; a -&gt; b)<br><br>-- instances for t = Either and/or t = (,)
<br>-- If h98 compatability is important, it could be split into two classes<br>-- or the functions lrAssocP and lrAssocE (specialized to pair/either)<br>-- could be put into CategoryPair and CategoryChoice respectively.<br>
-- Maybe this should be a super class of those two classes:<br>--&nbsp;&nbsp; class CategoryAssoc cat (,) =&gt; CategoryPair cat<br>--&nbsp;&nbsp; class CategoryAssoc cat Either =&gt; CategoryChoice cat<br>--&nbsp;&nbsp;Then we also have that rAssocP = swap . lAssocP . swap
<br>class Category cat =&gt; CategoryAssoc cat t where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lAssoc :: cat (t a (t b c)) (t (t a b) c)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rAssoc :: cat (t (t a b) c) (t a (t b c))<br><br><br>-- | &#39;cat&#39; contains all invertible functions (bijections)
<br>class Category cat =&gt; InvArrow cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arrInv :: (a -&gt; b) -&gt; (b -&gt; a) -&gt; cat a b<br><br>-- | &#39;cat&#39; contains all functional references<br>class InvArrow cat =&gt; RefArrow cat where<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arrRef :: (a -&gt; b) -&gt; (b -&gt; a -&gt; a) -&gt; cat a b<br><br>-- | &#39;cat&#39; contains all Haskell functions<br>class RefArrow cat =&gt; FunArrow cat where<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr :: (a -&gt; b) -&gt; cat a b<br><br>
<br>-- For backwards compatability:<br>-- These should be class aliases<br>class (FunArrow cat, CategoryPair cat) =&gt; Arrow cat<br>class (Arrow cat, CategoryChoice cat)&nbsp;&nbsp;=&gt; ArrowChoice cat<br>class (Arrow cat, CategoryZero cat)&nbsp;&nbsp;&nbsp;&nbsp;=&gt; ArrowZero cat
<br>class (Arrow cat, CategoryPlus cat)&nbsp;&nbsp;&nbsp;&nbsp;=&gt; ArrowPlus cat<br>class (Arrow cat, CategoryApply cat)&nbsp;&nbsp; =&gt; ArrowApply cat<br>class (Arrow cat, CategoryLoop&nbsp;&nbsp;cat)&nbsp;&nbsp; =&gt; ArrowLoop cat<br><br><br>I would further propose that all classes named Category* go into
<br>Control.Category, while Arrow* goes into Control.Arrow. The latter can<br>re-export the Control.Category module.<br><br>And while we are busy messing with the arrows, I think the Kleisli type<br>should change, it can be an instance of most of Category* with just
<br>Functor or Applicative instead of requiring the type to be a Monad.<br><br>Twan<br>_______________________________________________<br>Libraries mailing list<br><a href="mailto:Libraries@haskell.org">Libraries@haskell.org
</a><br><a href="http://www.haskell.org/mailman/listinfo/libraries">http://www.haskell.org/mailman/listinfo/libraries</a><br></blockquote></div><br>