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> <<a href="mailto:twanvl@gmail.com">twanvl@gmail.com</a>> 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>> 3. There might be another useful class that's a subclass of Category and<br>> a superclass of Arrow, that essentially includes first but not arr. If<br>> someone wants to name it and define it, we can put it in the class
<br>> hierarchy.<br><br><br>My proposal would be the following. The important things are that:<br> 1. It incorporates Conal's deep arrow,<br> 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> id :: cat a a<br> (.) :: cat b c -> cat a b -> cat a c<br><br><br>-- | 'cat' can work with pairs<br>
class Category cat => CategoryPair cat where<br> fst :: cat (a,b) a<br> snd :: cat (a,b) b<br> swap :: cat (a,b) (b,a)<br> first :: cat a b -> cat (a,c) (b,c)<br> second :: cat a b -> cat (c,a) (c,b)
<br> (***) :: cat a b -> cat c d -> cat (a,c) (b,d)<br><br> snd = fst . swap<br> second f = swap . first f . swap<br> f *** g = second g . first f<br><br>class CategoryPair cat => CategoryFanOut cat where
<br> (&&&) :: cat a b -> cat a c -> cat a (b,c)<br> dup :: cat a (a,a)<br><br> f &&& g = f *** g . dup<br><br><br>-- | 'cat' can work with eithers<br>-- Dual to CategoryPair
<br>class Category cat => CategoryChoice cat where<br> inl :: cat a (Either a b)<br> inr :: cat b (Either a b)<br> mirror :: cat (Either a b) (Either b a)<br> left :: cat a b -> cat (Either a c) (Either b c)
<br> right :: cat a b -> cat (Either c a) (Either c b)<br> (+++) :: cat a b -> cat c d -> cat (a,c) (b,d)<br><br> inr = mirror . inl<br> right f = mirror . left f . mirror<br> f +++ g = right g . left f
<br><br>class CategoryChoice cat => CategoryFanIn cat where<br> (|||) :: cat a c -> cat b c -> cat (Either a b) c<br> untag :: cat (Either a a) a<br><br> f ||| g = untag . f +++ g<br><br><br>class Category cat => CategoryZero cat where
<br> zeroCat :: cat a b<br><br>class CategoryZero cat => CategoryPlus cat where<br> (<+>) :: cat a b -> cat a b -> cat a b<br> -- this is what ArrowPlus uses, but perhaps<br> -- (///) is a better choice, because it looks more like the others.
<br><br><br>class CategoryPair cat => CategoryApply cat where<br> app :: cat (cat a b, a) b<br><br><br>class CategoryPair cat => CategoryLoop cat where<br> loop :: cat (a,c) (b,c) -> cat a b<br><br>-- no idea how useful this is, but it is nice for symmetry
<br>class CategoryChoice cat => CategoryCoLoop cat where<br> coloop :: cat (Either a c) (Either b c) -> cat a b<br><br><br>-- | Categories that can manipulate functions.<br>-- This is most of 'DeepArrow'.
<br>class Category cat => CategoryFun cat where<br> result :: cat b c -> cat (a -> b) (a -> c)<br> curry :: cat ((a, b) -> c) (a -> b -> c)<br> uncurry :: cat (a -> b -> c) ((a, b) -> c)
<br> funF :: cat (c -> a, b) (c -> (a, b))<br> funS :: cat (a, c -> b) (c -> (a, b))<br> funR :: cat (a -> c -> b) (c -> a -> 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>-- class CategoryAssoc cat (,) => CategoryPair cat<br>-- class CategoryAssoc cat Either => CategoryChoice cat<br>-- Then we also have that rAssocP = swap . lAssocP . swap
<br>class Category cat => CategoryAssoc cat t where<br> lAssoc :: cat (t a (t b c)) (t (t a b) c)<br> rAssoc :: cat (t (t a b) c) (t a (t b c))<br><br><br>-- | 'cat' contains all invertible functions (bijections)
<br>class Category cat => InvArrow cat where<br> arrInv :: (a -> b) -> (b -> a) -> cat a b<br><br>-- | 'cat' contains all functional references<br>class InvArrow cat => RefArrow cat where<br>
arrRef :: (a -> b) -> (b -> a -> a) -> cat a b<br><br>-- | 'cat' contains all Haskell functions<br>class RefArrow cat => FunArrow cat where<br> arr :: (a -> b) -> cat a b<br><br>
<br>-- For backwards compatability:<br>-- These should be class aliases<br>class (FunArrow cat, CategoryPair cat) => Arrow cat<br>class (Arrow cat, CategoryChoice cat) => ArrowChoice cat<br>class (Arrow cat, CategoryZero cat) => ArrowZero cat
<br>class (Arrow cat, CategoryPlus cat) => ArrowPlus cat<br>class (Arrow cat, CategoryApply cat) => ArrowApply cat<br>class (Arrow cat, CategoryLoop cat) => 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>