t2 = (\x y z-> x.y.x)
GHCI shows me this:
t2 :: (b1 -> b2) -> (b2 -> b1) -> p -> b1 -> b2
I can't quite grasp it how this type signature comes to be. So far I've figured that the righter-most x is basically a function which takes a b2
and returns a b1
, then that b1
is the input of the middle function y
, and outputs b2
again? Should it not return a value of a new type b3
or something?
First let's rewrite this in a way that makes it clear which argument corresponds to which part of the type signature:
t2 :: (b1->b2) -> (b2->b1) -> p -> b1 -> b2
t2 x y z = x . y . x
z :: p
isn't used at all, so we can easily eliminate this by instead considering
t3 :: (b1->b2) -> (b2->b1) -> b1 -> b2
t3 x y = x . y . x
Why is that the type? Well, the composition chain feeds the result of x
into y
, and the result of y
back into x
. In other words, y
gets you from the result type of x
back to the argument type of x
. Therefore the type of y
must be the “inverted” type of x
. So
t3 :: (m->n) -> (n->m) -> ?
t3 x y = x . y . x
The type of the composition is dominated by the “outer ends”, i.e. the argument must be the type of argument for x
and the result must be the type of result of... again, x
. Hence
t3 :: (m->n) -> (n->m) -> m->n
t3 x y = x.y.x
which is what GHCi told you, with renamed type variables.