tl;dr
Given the similarity between ixmap's signature and contramap's signature, I'd like to understand if Array i e is a contravariant functor in its first type argument or, at least, how the two things relate to each other from a category theory standpoint.
Longer lucubration
At the end of Chapter 12 from Real World Haskell, the function ixmap is used.
Based on its signature
ixmap :: (Ix i, Ix j) => (i, i) -> (i -> j) -> Array j e -> Array i e
I couldn't help but notice that, once we partially apply it to the first argument, e.g. we pass to it (1 :: Int, 1 :: Int) for simplicity, its signature becomes
ixmap (1 :: Int,1 :: Int) :: Ix j => (Int -> j) -> Array j e -> Array Int e
which has some similarity with the signature of contramap:
contramap :: (a' -> a) -> f a -> f a'
and even more with the specialization of it for Op:
contramap :: (a' -> a0) -> Op a a0 -> Op a a'
After all, I think, the type Array j e can be though of as the type of a function mapping a subset of type j to type e, kind of j -> a with a "restricted" j. So, just like b -> a is a Functor in a and Op a b was defined to make it a contravariant functor in b, I thought I could similarly define:
newtype Array' e i = Array' { arr :: Array i e }
and write a Contravariant instance for it:
instance Contravariant (Array' e) where
contramap f a = undefined -- ???
What disturbs me is that I can't really use a partially applied ixmap for contramap because (1) what I do partially apply it to? And (2) doing it would block the i type (e.g. to Int in my example).
And I can't even think of a way for contrampa to retrie the required object of type (i,i) from the other two arguments f :: (i -> j) and a :: Array j e, because I have no function to go from j to i.
Ix iconstraint prevents the definition ofcontramapsince the latter does not allow constraints. This is the same issue which preventsFunctor Set, for instance, where we cannot addOrdas a requirement. I guess you will need a "constrained contravariant functor" typeclass, distinct fromContravariant. - chi