Work backwards, and assign type variables until they are specified:
-- We assign types one by one:
(.) x (y z) :: a -- So,
(y z) :: b
(.) x :: b -> a
x :: c
(.) :: c -> b -> a
But we know that (.) :: (y -> z) -> (x -> y) -> (x -> z)
, so, we can equate some types, written with ~
:
c ~ y -> z
b ~ x -> y
a ~ x -> z
We now know that:
x :: y -> z
(.) x (y z) :: x -> z
y z :: x -> y
So
z :: d
y :: d -> x -> y
Finally, we just complete the type of the function
-- (type of x) (Type of y) (type of z) (return type)
(\x y z -> x . y z) :: (y -> z) -> (d -> x -> y) -> d -> (x -> z)
Finally, we can ask GHCi for confirmation:
Prelude> :t (\x y z -> x . y z)
(\x y z -> x . y z) :: (b -> c) -> (t -> a -> b) -> t -> a -> c