It's been claimed that newtype T a = T (a -> Int)
is a type constructor that is not a functor (but is a contravariant functor). How so? Or what is the contravariant functor (whence I assume it will be obvious why this can't be made a normal functor)?
Given
newtype T a = T (a -> Int)
let's try to build the Contravariant
instance for this datatype.
Here's the typeclass in question:
class Contravariant f where
contramap :: (a -> b) -> f b -> f a
Basically, contramap
is akin to fmap
, but instead of lifting a function a -> b
to f a -> f b
, it lifts it to f b -> f a
.
Let's begin writing the instance...
instance Contravariant T where
contramap g (T f) = ?
Before we fill in the ?
, let's think about what the types of g
and f
are:
g :: a -> b
f :: b -> Int
And for clarity, we might as well mention that
f a ~ T (a -> Int)
f b ~ T (b -> Int)
So we can fill in the ?
as follows:
instance Contravariant T where
contramap g (T f) = T (f . g)
To be super pedantic, you might rename g
as aToB
, and f
as bToInt
.
instance Contravariant T where
contramap aToB (T bToInt) = T (bToInt . aToB)
The reason you can write a Contravariant
instance for T a
boils down to the fact that a
is in contravariant position in T (a -> Int)
. The best way to convince yourself that T a
isn't a Functor
is to try (and fail) to write the Functor
instance yourself.