9

Some instances of Category are also instances of Functor. For example:

{-# LANGUAGE ExistentialQuantification, TupleSections #-}

import Prelude hiding (id, (.))
import Control.Category
import Control.Arrow

data State a b = forall s. State (s -> a -> (s, b)) s

apply :: State a b -> a -> b
apply (State f s) = snd . f s

assoc :: (a, (b, c)) -> ((a, b), c)
assoc (a, (b, c)) = ((a, b), c)

instance Category State where
    id = State (,) ()
    State g t . State f s = State (\(s, t) -> assoc . fmap (g t) . f s) (s, t)

(.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
(.:) = fmap . fmap

instance Functor (State a) where
    fmap g (State f s) = State (fmap g .: f) s

instance Arrow State where
    arr f = fmap f id
    first (State f s) = State (\s (x, y) -> fmap (,y) (f s x)) s

Here arr f = fmap f id for instance Arrow State. Is this true for all instances of Category which are also instances of Functor? The type signatures are:

arr               ::                 Arrow    a  => (b -> c) -> a b c
(\f -> fmap f id) :: (Functor (a t), Category a) => (b -> c) -> a b c

It seems to me that they should be equivalent.

duplode
  • 33,731
  • 7
  • 79
  • 150
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • 1
    At the very least, the `Arrow` laws are enough to *define* a law-abiding `Functor` instance by `instance Arrow a => Functor (a s) where fmap f v = v >>> arr f`. Perhaps that together with parametricity is enough to ensure that this is also the *only* law-abiding instance, though I haven't worked out the details so I won't claim it to be true. – Daniel Wagner Jul 24 '15 at 20:13
  • Remember that, for functions and arrows, `fmap` should equal `(<<<)`. – AJF Jul 24 '15 at 20:31
  • [This comment](http://stackoverflow.com/questions/28395214/automatic-functor-instance#comment45136634_28395214) suggests that I was correct: parametricity guarantees at most one law-abiding `Functor` instance. So the answer to your question seems to be "yes". – Daniel Wagner Jul 24 '15 at 20:40
  • 1
    Since `arr` is a method of `Arrow`, not `Category`, I am still somewhat skeptical - I doubt every `Category` that also is a `Functor` needs to be an `Arrow`. The reverse is true, however, as every `Arrow` [gives not just a `Functor`, but an `Applicative`](https://cdsmith.wordpress.com/2011/07/30/arrow-category-applicative-part-i/). – Ørjan Johansen Jul 24 '15 at 22:13
  • @ØrjanJohansen "I doubt every `Category` that also is a `Functor` needs to be an `Arrow`" - indeed, though the underlying issue is that `arr` and `first` are, as leftaroundabout says below, "quite separate things combined". – duplode Jul 25 '15 at 03:57

2 Answers2

6

First let's be clear what Arrow C means. Well, it's two quite separate things combined – in my book,

arr comes from the latter. “Generalise” Hask? What this means is just to have a mapping from the category Hask to C. – And mathematically, mapping from one category to another is exactly what a functor does! (The standard Functor class actually covers only a very specific sort of functors, namely endofunctors on Hask.) arr is the morphism-aspect of a non-endofunctor, namely the “canonical embedding functor” HaskC.

From this point of view, the first two arrow laws

arr id = id
arr (f >>> g) = arr f >>> arr g

are just the functor laws.

Now, what does it mean if you're implementing a Functor instance for a category? Why, I daresay it simply means you're expressing that same canonical embedding functor, but via the necessary representation of C back in Hask (which makes it an endofunctor overall). Hence I'd argue that yes, \f -> fmap f id should be equivalent to arr, since basically they're two ways of expressing the same thing.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • 1
    @duplode: actually not. I posted the wrong link (`Function` does the opposite thing, it's the class of specialised, rather than generalised functions). This is how it would be correct: “In terms of `constrained-categories`, every `Category C` which is also a `Functor C (->) (->)` is an `EnhancedCat C (->)` as well”. – leftaroundabout Jul 25 '15 at 12:28
3

Here is a derivation to supplement leftaroundabout's explanation. For clarity, I will reserve (.) and id for (->), and use (<<<) and id' for the general Category methods.

We begin with preComp, also known as (>>>):

preComp :: Category y => y a b -> (y b c -> y a c)
preComp v = \u -> u <<< v

fmap commutes with natural transformations between Hask endofunctors. For a Category which also has a Functor instance, preComp v is a natural transformation (from y b to y a), and so it commutes with fmap. It follows that:

fmap f . preComp v = preComp v . fmap f
fmap f (u <<< v) = fmap f u <<< v
fmap f (id' <<< v) = fmap f id' <<< v
fmap f v = fmap f id' <<< v

That's our candidate arr! So let's define arr' f = fmap f id'. We can now verify that arr' follows the first arrow law...

-- arr id = id'
arr' id
fmap id id'
id'

... and the second one too:

-- arr (g . f) = arr g <<< arr f
arr' (g . f)
fmap (g . f) id'
(fmap g . fmap f) id'
fmap g (fmap f id')
fmap g (arr' f)
fmap g id' <<< arr' f -- Using the earlier result.
arr' g <<< arr' f

I suppose that is as far as we can get. The other five arrow laws involve first, and as leftaroundabout points out arr and first are independent.

duplode
  • 33,731
  • 7
  • 79
  • 150