First, I agree with you: functions are not very intuitive, like functors, and I sometimes want these instances not to be there. It is not that they are sometimes not useful, but quite often they are used in a useless and confusing manner. These methods can always be replaced either by more specific combinators (in particular, from Control.Arrow ), or with an equivalent, but somehow more descriptive reader monad .
However ... to understand the functor of a function, I suggest you first consider Map . In a sense, Map Int very similar to an array: it contains some elements that you can convert (i.e. fmap over), and you can access individual elements by indexing them with integers. Map simply allows the "array" to have spaces in it and generalizes from whole indices to any type of index that you can order.
In another view, however, Map is just a concrete implementation of a function: it maps arguments (keys) to results (values). And this should clearly show how the functor of the function works: it displays all the possible results of the function β .
This explanation, unfortunately, does not explain the Monad instance much, because Map does not actually have a monad instance (or even Applicative ). Direct adaptation of the list / array implementation would really be impossible ... recap: in lists we have
pure x β‘ [x] (,) <$> [a,b] <*> [x,y,z] β‘ [(a,x),(a,y),(a,z),(b,x),(b,y),(b,z)]
therefore, after combining, the indices are all different. This may not work for Map , where we want to support shared keys.
However, there is an alternative monad instance for the list, the zip list:
pure x β‘ repeat x (,) <$> [a,b] <*> [x,y,z] β‘ [(a,x),(b,y)]
Please note that item indices are saved.
Now this instance can really be adapted for Map , provided that the repeat :: a -> Map ka generator exists. This does not exist, because in the general case there are infinitely many keys, and we cannot list all of them and balance the infinite tree that such a Map entails. But if we restrict ourselves to key types with a finite number of possible values ββ(for example, Bool ), then we are good:
instance Applicative (Map Bool) where pure x = Map.fromList [(False, x), (True, x)] <*> = Map.intersectWith ($)
Now, how the monad function works, unlike Map there is no problem if an infinite number of different arguments are possible, because you never try to save them all with associated values; rather, you always only calculate the values ββin place.
β It would not be feasible if it werenβt done lazily - which in Haskell is hardly a problem, in fact, if you fmap over a Map , it also happens lazily. For a functional functor, fmap is actually not just lazy, but the result is also immediately forgotten and needs to be recalculated.