Stating the law again for ease of reference (which I have corrected by putting the parenthese in, `(<*>) is left associative so the ones on the LHS of the equality are necessary):
x <*> (y <*> z) = ( pure (.) <*> x <*> y) <*> z
let's start with your first question:
On the right hand side of the law,
does pure (.) have type f((b -> c) -> (a -> b) -> (a -> c))?
Yes it does. (.)
has type (b -> c) -> (a -> b) -> (a -> c)
, so pure (.)
must have type "f
of that".
We can use this to determine the types of the other identifiers here. In the expression m <*> n
, m
and n
have the general types f (a -> b)
and f a
. So if we take m
as (.)
, which has the type shown above, we see that n
- which corresponds to x
on the RHS of the equality - must have type f (b -> c)
. And then pure (.) <*> x
will have type f ((a -> b) -> (a -> c))
, which by the same reasoning means y
will have type f (a -> b)
. This produces a type of f (a -> c)
for ( pure (.) <*> x <*> y)
and of f a
for z
- and thus an overall result type, for the whole RHS (and therefore also the whole LHS) of f c
.
So to summarise, just from analysing the RHS, we see that:
x :: f (b -> c)
y :: f (a -> b)
z :: f a
It's now easy to check that these work out on the LHS too - y <*> z
will have type f b
, so x <*> (y <*> z)
will have type f c
.
I note that there's nothing clever involved in the above, it's just simple type algebra, which can be carried out without any advanced understanding.