
Conal Elliott wrote:
While we're at it, how about one or more classes in between Category/Compositor and Arrow?
While looking into functional references I came up with the heirarchy:
class Category (~>) where id :: a ~> a (.) :: (b ~> c) -> (a ~> b) -> (a ~> c)
class Cagegory (~>) => InvArrow (~>) where -- | invArr f g may only be used if g . f = id = f. g invArr :: (a -> b) -> (b -> a) -> (a ~> b)
class InvArrow (~>) => RefArrow (~>) where refArr :: (a -> b) -> (b -> a -> a) -> (a ~> b)
class RefArrow (~>) => Arrow (~>) where arr :: (a -> b) -> (a ~> b)
InvArrow allows invertible functions to be lifted to the arrow type, while RefArrow lifts functional references. I am not too happy about the names, but I like the idea itself. apfelmus wrote:
class Cartesian cat where fst :: cat (a,b) a snd :: cat (a,b) b (&&&) :: cat c a -> cat c b -> cat c (a,b)
with the conditions
fst . (f &&& g) = f snd . (f &&& g) = g
That is not correct, fst . (f &&& g) also has the side effects of g.
get first and second and that would be everything we need for arrows (besides arr ). But IIRC, (&&&) does impose an "order of side effects" on the arguments, so Arrows are more general
For the InvArrow of invertible functions:
data Invertible a b = Invertible { fun :: a -> b, inverse :: b -> a }
The functions (***), first and second are definable, while fan out, (&&&) is not. What I came up with was:
class Category (~>) => CategoryPair (~>) where first :: (a ~> b) -> ((a,d) ~> (b,d)) second :: (a ~> b) -> ((d,a) ~> (d,b)) (***) :: (a ~> b) -> (c ~> d) -> ((a,c) ~> (b,d)) swap :: (a,b) ~> (b,a)
class CategoryPair (~>) => CategoryFanOut (~>) where (&&&) :: (a ~> b) -> (a ~> c) -> (a ~> (b,c))
Exactly the same problem comes up for ArrowChoice and the fan out operator (|||), again the class can be split in two. I am not sure how this should be combined with Conal's deep arrows, perhaps fst and snd could be added to CategoryPair as well. Twan