The functor f
in your example is the so-called “reader-functor”, which is defined as follows:
newtype Reader r = Reader (r -> a)
Of course, in Haskell this is implemented initially for functions, so there is no wrapping or deployment at run time.
The corresponding Functor
and Applicative
instances are as follows:
instance Functor f where fmap :: (a -> b) -> (r -> a)_-> (r -> b) fmap fg = \x -> f (gx) -- or: fmap = (.) instance Applicative f where pure :: a -> (r -> a) -- or: a -> r -> a pure x = \y -> x -- or: pure = const (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b) frab <*> fra = \r -> frab r (fra r)
In a sense, a functor reader is a “box”, like all other functors, having a context r
that creates a type a
.
So, look at (,) <$> sum
:
:t (,) :: a -> b -> (a, b) :t fmap :: (d -> e) -> (c -> d) -> (c -> e) :t sum :: Foldable t, Num f => tf -> f
Now we can specialize type d
to a ~ f
, e
to b -> (a, b)
and c
to tf
. Now we get:
:t (<$>) -- spcialized for your case :: Foldable t, Num f => (a -> (b -> (a, b))) -> (tf -> f) -> (tf -> (b -> (a, b))) :: Foldable t, Num f => (f -> b -> (f, b)) -> (tf -> f) -> (tf -> b -> (f, b))
Application Functions:
:t (,) <$> sum :: Foldable t, Num f => (tf -> b -> (f, b))
This is exactly what ghc says.