We can try to arrive at some more easily understood formulation first, so that its type becomes "obvious". We have
(,) <$> length <*> head
=
pure (,) <*> length <*> head
=
liftA2 (,) length head
for any Applicative, by the Applicative laws and the definition of liftA2.
So we have (,) combining the contained / carried / produced results from the applicative values length and head:
(,)
/ \
/ \
length head
But length and head are functions, and for functions we have
(,)
/ \
/ \
length head
\ /
\ /
x
i.e.
liftA2 (,) length head x
=
(,) (length x) (head x)
by the definition of the (->)'s Applicative instance.
Thus the type of (,) <$> length <*> head is the type of liftA2 (,) length head is the type of \ x -> (length x , head x). And that is "obviously" "just" [a] -> (Int , a).
GHCi concurs:
> :t \ x -> (length x , head x)
\ x -> (length x , head x) :: [t] -> (Int, t)
> :t (,) <$> length <*> head
(,) <$> length <*> head :: [a] -> (Int, a)
length :: Foldable t => t a -> Int is defined for any Foldable but head :: [a] -> a works on lists specifically, so length's type becomes specialized as [a] -> Int.
And head produces the same type that the elements of the input list have:
(Int,a) ~ (,) Int a
/ \ | |
/ \ | |
length \ :: [a] -> Int |
\ head :: [a] -> a
\ / |
\ / |
[a] ~ [a]
So there's no "switching". Everything flows.