Brent Yorgey's Typeclassopedia gives the following exercise:
Give an example of a type of kind
* -> *which cannot be made an instance ofFunctor(without usingundefined).
Please tell me what "cannot be made an instance of Functor" means.
Also, I'd appreciate an example, but perhaps as a spoiler so that you can, please, guide me to the answer.
Let's talk about variances.
Here's the basic notion. Consider the type
A -> B. What I want you to imagine is that such a type is similar to "having aB" and also "owing anA". In fact, if you pay back yourAyou immediately receive yourB. Functions are kind of like escrow in that way.The notion of "having" and "owing" can extend to other types. For instance, the simplest container
behaves like this: if you "have" a
Box athen you also "have" ana. We consider types which have kind* -> *and "have" their argument to be (covariant) functors and we can instantiate them toFunctorWhat happens if we consider the type of predicates over a type, like
in this case, if we "have" a
Pred a, we actually "owe" ana. This arises from theabeing on the left side of the(->)arrow. WherefmapofFunctoris defined by passing the function into the container and applying it to all the places where we "have" our inner type, we can't do the same forPred asince we don't "have" andas.Instead, we'll do this
Now that
contramapis like a "flipped"fmap? It will allow us to apply the function to the places where we "own" abinPred bin order to receive aPred a. We might callcontramap"barter" because it encodes the idea that if you know how to getbs fromas then you can turn a debt ofbs into a debt ofas.Let's see how it works
we just run our trade using
fprior to passing it on into the predicate function. Wonderful!So now we have covariant and contravariant types. Technically, these are known as covariant and contravariant "functors". I'll also state immediately that almost always a contravariant functor is not also covariant. This, thus, answers your question: there exist a bunch of contravariant functors which are not able to be instantiated to
Functor.Predis one of them.There are tricky types which are both contravariant and covariant functors, though. In particular, the constant functors:
In fact, you can essentially prove that anything which is both
ContravariantandFunctorhas a phantom parameter.On the other hand, what happens with a type like
In
Endo awe both owe and receive ana. Does that mean we're debt free? Well, no, it just means thatEndowants to be both covariant and contravariant and does not have a phantom parameter. The result:Endois invariant and can instantiate neitherFunctornorContravariant.