This explanation is useless imo because it expects the reader to already understand the weirdest part:
"If I have a function A -> B, how could I possibly get something that goes in the direction F B -> F A out of it?"
The answer to this is: given e.g. a function that accepts a B, i.e. `B -> ...` you can compose it with `A -> B` on the _input side_, to get a function that accepts an A, i.e. `A -> B` (+) `B -> ...` = `A -> ...`.
Once you've managed to get that across, you can start talking about contravariant functors. But expecting people to just intuit that from the condensed type signature is pedagogical nonsense.
Single-argument doesn't capture the difference between functor and applicative.
ex1 :: Functor f => f (Int, Int) -> f Int
ex1 = map (uncurry (+))
Applies a multi-argument function within a functor. What applicative allows you do is take a product of contexts to a context of products, and lift a value to a context.
pure :: a -> f a
zip :: (Applicative f) => (f a, f b) -> f (a, b)
This can then be used to make ex1 into a multi-argument function of contexts, which is not the same as (uncurry (+)) being a multi-argument function
ex2 :: (Functor f) => (f Int, f Int) -> f Int
ex2 = ex1 . zip
No a functor is a "function" over types that can transport the arrows:
(A -> B) -> (F A -> F B) for a covariant functor
(A -> B) -> (F B -> F A) for a contravariant functor
With the sum and product there is also the exponential:
B^A = functions from A to B