### Pulling Apart haskell’s Arrow Types.

#### by geekagent

Haskell arrows are a strange beast. Most people have a hard time understanding them, and the people that do often see things that are almost arrows but don’t meet 1 of the criteria. For example stream transformers don’t have a valid instance of `***`

, but they do have an instance for `arr`

, and for `+++`

and `|||`

. I recently went over them and figured out exactly what each constraint implies.

As Dan Piponi has pointed out, arrows are profunctors. Another way to think about them is that arrows define a category whose objects are haskell types. It’s interesting to ask about what the relations between Hask and this other category are. So here are some possible relations:

Throughout the rest, the non-Hask category will be called C.

- There is a functor from Hask to C. This is witnessed by
`arr`

in the standard arrow package. Note that this is mostly independent from the rest of the relations below, except that if the relations below exist there’s a commuting diagram with`arr.`

- The Haskell product is the product in C. Witnessed by
`&&&`

. - The Haskell product is a monoid in C. Witnessed by
`***`

. This is weaker than above. e. g. Op satisfies this, but not the above. (,) is the sum in Op, but it’s still a monoid - The Haskell sum is a sum in C. Witnessed by
`|||`

. - The Haskell sum is a monoid in C. Witnessed by
`+++`

. As above, this is weaker - The Haskell product is the product in C, and the type c a b is the exponential in C. This is witnessed by the co-unit of the adjunction:
`eval`

. The Haskell arrow package calls this`app`

I’ve written these out as code below.

*Note that it’s probably possible to be even more general in Haskell and ask whether C has some other product, or some other sum.

and then define the same usfeful functions when it happens to be the Haskell sum and the Haskell product, but I wanted to map out exactly what Arrow was asking for first.

```
module Category where
import Prelude hiding (fst,snd,(.),id)
import Control.Category
{-
Since the objects of this other category are haskell types describing a functor
between the two is as simple as describing its action on functions. arr does
exactly this
-}
class (Category c) => CategoryFunctor c where
arr :: (a -> b) -> c a b
class (Category c) => ProductIsMonoid c where
(***) :: (c a1 b1) -> (c a2 b2) -> (c (a1,a2) (b1,b2))
class (ProductIsMonoid c) => ProductIsCommutatitve c where
cSwap :: (c (a,b) (b,a))
{-
If defining both instances, *** can be defined in terms of &&& as follows:
f *** g = (fst >>> f) &&& (snd >>> g)
-}
class (ProductIsMonoid c) => ProductIsProduct c where
(&&&) :: (c a b1) -> (c a b2) -> (c a (b1, b2))
fst :: (c (a,b) a)
snd :: (c (a,b) b)
class (Category c) => SumIsMonoid c where
(+++) :: (c a1 b1) -> (c a2 b2) -> (c (Either a1 a2) (Either b1 b2))
{-
If defining both instances, +++ can be defined in terms of ||| as follows:
f +++ g = (f >>> left) ||| (g >>> right)
-}
class (SumIsMonoid c) => SumIsSum c where
(|||) :: (c a1 b) -> (c a2 b) -> c (Either a1 a2) b
left :: c a (Either a b)
right :: c b (Either a b)
class (ProductIsProduct c) => ProductIsClosed c where
eval :: (c (c a b, a) b)
{-
Here we define instances for (->). (->) Has all the instances, because it is the
same category
-}
instance CategoryFunctor (->) where
arr = id
instance ProductIsMonoid (->) where
(***) f g (x,y) = (f x, g y)
instance ProductIsProduct (->) where
(&&&) f g x = (f x, g x)
fst (x,y) = x
snd (x,y) = y
instance ProductIsCommutatitve (->) where
cSwap (x, y) = (y, x)
instance SumIsMonoid (->) where
(+++) f g (Left x) = Left $ f x
(+++) f g (Right x) = Right $ g x
instance SumIsSum (->) where
(|||) f g (Left x) = f x
(|||) f g (Right x) = g x
left = Left
right = Right
instance ProductIsClosed (->) where
eval = uncurry ($)
-- Here's a type where we can define some, but not all of the instances.
newtype Op a b = Op (b->a)
instance Category Op where
id = id
(Op f) . (Op g) = Op $ g . f
instance ProductIsMonoid Op where
(Op f) *** (Op g) = Op $ f *** g
instance SumIsMonoid Op where
(Op f) +++ (Op g) = Op $ f +++ g
```