Why does the following typecheck? - haskell

Why does the following typecheck?
cancel x y = x
distribute f g x = f x (g x)
identity = distribute cancel cancel
Clearly cancel :: a -> b -> a, distribute :: (a -> b -> c) -> (a -> b) -> a -> c and identity :: a -> a. Now, distribute cancel :: (a -> b) -> a -> a, but I don't understand why cancel matches with a -> b.
Could anyone explain this to me?

Let's make all the type variables distinct:
identity = distribute cancel1 cancel2
where distribute :: (a -> b -> c) -> (a -> b) -> a -> c
cancel1 :: x -> y -> x
cancel2 :: r -> s -> r
So, simply lining up the types we need to unify to prove that distribute call checks out:
distribute :: (a -> b -> c) -> (a -> b) -> a -> c
cancel1 :: x -> y -> x
cancel2 :: r -> s -> r
cancel1 is obvious; we have:
a ~ x
b ~ y
c ~ x
(The ~ sign is basically how we write equality of types in Haskell; you can use it in actual code if you turn on some extensions)
Let's substitute those in
distribute :: (x -> y -> x) -> (x -> y) -> x -> x
cancel1 :: x -> y -> x
cancel2 :: r -> s -> r
For the next bit, we need to remember that the arrow is a binary operator. It takes exactly two parameters: an argument type and a result type.So if we've got a function type with two arrows one of them must be inside the argument type or result type of the other. In a case like r -> s -> r, we're using the right associativity of -> to leave out parentheses that would make it obvious: it's really r -> (s -> r).1
So then:
distribute :: (x -> y -> x) -> (x -> y ) -> x -> x
cancel1 :: x -> y -> x
cancel2 :: r -> (s -> r)
So now we can immediately read off:
x ~ r
y ~ s -> r
More substitution:
distribute :: (r -> (s -> r) -> r) -> (r -> (s -> r)) -> r -> r
cancel1 :: r -> (s -> r) -> r
cancel2 :: r -> (s -> r)
So the thing that cancel1 is ignoring is a function of type s -> r, which is also what cancel2 returns. Remembering the f x (g x) implementation of distribute, this makes sense. cancel1 and cancel2 both have to be called with the same thing; cancel1 then receives the result of calling cancel2 as its second argument, which it promptly ignores, so it doesn't matter what the type of cancel2's second parameter is as it's never actually called on another argument (any function at all that accepts r as its first parameter would have worked here). This is all an elaborate way to write a function that does nothing: identity.
1 If you have trouble remembering whether -> is right or left associative, you may have heard that all Haskell functions take a single argument and we commonly "fake" multiple-argument functions by using functions that return other functions. That's what's going on here, and why the function arrow associates to the right.

cancel has type a -> b -> a, but that's the same as a -> (b -> a), so it's a function type with a input and b -> a output.
a -> b matches any function type whatsoever; in this case, a matches a and b matches b -> a.
distribute cancel (\a b c -> a) checks out similarly. Haskell functions are curried, so there's always just a single input type and a single return type, but the return type can also be a function.

Related

How does type unification/function application work at a high level in Haskell?

I feel like I'm not really getting how function application works or maybe I'm fixating on something that I shouldn't be.
Let's try to determine the type signature of (fmap .)
fmap :: (x -> y) -> f x -> f y
(.) :: (b -> c) -> (a -> b) -> a -> c -- signatures taken from GHC
Applying fmap to (.), we esentially wanna make (x -> y) -> f x -> f y and (b -> c) equal. When I first tried to do this I remember having a really hard time. You gotta match a set of 4 variables to a set of 2, so obviously you gotta do some grouping, but how? There's 3 possible solutions that I see, are all of them valid? Or is it only 1? I read that parentheses aren't really taken into consideration by the compiler, so we end up with x -> y -> f x -> f y and b -> c, but also functions associate to the right, so fmap should actually look like x -> (y -> (f x -> f y)), which lead me to
b = x
c = y -> f x -> f y
resulting in (a -> x) -> (a -> y -> f x -> f y) as a signature for (fmap .).
The grouping I've seen this solved with though is (a -> b) -> (f a -> f b). So
b = x -> y
c = f x -> f y
leading to (a -> x -> y) -> a -> f x -> f y, which is more or less the same as GHC's (a1 -> a2 -> b) -> a1 -> f a2 -> f b if you rename some type variables.
Now to compare the 2 results, parentheses removed:
a -> x -> a -> y -> f x -> f y
a -> x -> y -> a -> f x -> f y
We can clearly see that the 3rd and 4th parameter types are switched, which means they're obviously not the same since flip is a thing. Which means this substitution
b = x
c = y -> f x -> f y
is not valid. Or am I missing something?
I have a feeling that I'm trying to make the functions work based on the signatures when I should be doing it the other way around. :t fmap 'c' fails with Couldn't match expected type 'a -> b' with actual type 'Char' which means that you can't really
partially apply the a -> b part of fmap. You can only partially apply fmapitself and its first argument is indivisible I guess. I don't know if I'm getting the pattern behind it all though.
I should really try to write a typed lambda calculus.
There's 3 possible solutions that I see, are all of them valid?
No.
Or is it only 1?
Only one. (x -> y) -> f x -> f y is equal to (x -> y) -> (f x -> f y) and only to that since -> is right associative. Putting parentheses in other points is wrong.
I read that parentheses aren't really taken into consideration by the compiler,
That's false. The compiler implicitly works as parentheses are always added in a right-associative way: the type a -> b -> c -> d is handled as a -> (b -> (c -> d)), only. By contrast, the type (a -> b) -> c -> d is handled as (a -> b) -> (c -> d), only, and the type (a -> b -> c) -> d is handled as (a -> (b -> c)) -> d, only.
so we end up with x -> y -> f x -> f y and b -> c,
No, that's wrong, you must keep the parentheses.
We must satisfy the type equality
(x -> y) -> (f x -> f y)
~
b -> c
and the unique solution to this is
b ~ (x -> y)
c ~ (f x -> f y)
as you found out later.
To understand what's going on in unification, I think it's beneficial if you start by adding the implicit parentheses in a right-associative way. If you do that, you can forget about types like a -> b -> c, and only care about the fundamental case (T -> U) and its unification step:
from (T1 -> U1) ~ (T2 -> U2)
deduce T1 ~ T2 and U1 ~ U2

Defining a function that satisfies a type in Haskell

Considering the type
foo :: a -> ((b -> a) -> c) -> c
I want to create a function that satisfies this type...
I know foo x y = y (\z -> x) satisfies this type as confirmed with :type in GHCi, but how would I get to this final function manually, or step by step?
I also know foo2 f g = \x -> f (g x) would also satisfy foo2 :: (a -> b) -> (c -> a) -> c -> b but don't also know how to get to this function.
It's just a matter of fitting the matching pieces of a puzzle together. The same-named pieces match. The type of foo means it's a function with two parameters:
foo :: a -> ((b -> a) -> c) -> c
-- a f
foo a f = c
-- a :: a
-- f g :: c
-- g b :: a
where
c = f g -- produce a c-type value
g b = a -- define g to produce
-- the value a
f we're given, but g we must invent so that it returns a; fortunately, we're already given an a:
-- f :: ((b -> a) -> c)
-- g
-- g :: b -> a
a is given to us as a parameter of foo, and b is just an unused parameter of g.
Next we can substitute and simplify, using the fact that writing this:
p :: q -> r
p q = r...
is the same as writing this:
p :: q -> r
p = \q -> r...
where we use r... to indicate an expression whose type is r.
Also, s -> t -> r is the same as s -> (t -> r) because, similarly,
h :: s -> t -> r
h s t = r...
h s = (\t -> r...)
h = \s -> (\t -> r...)
all express the same thing.
Your second question can be addressed in the same manner.
x :: a means "the value x has type a"; a :: a means "the value a has type a". The same name a can be used in two different roles; when you're accustomed to it, it can actually be quite a helpful mnemonic.
See also.
An underscore _, or an undefined name beginning with an underscore such as _what, is treated by GHC as a “hole” that you want to fill in. You can use this to ask what type the compiler is expecting, and this can be helpful in figuring out how to iteratively fill in the program. Thankfully, this is a case where it’s very helpful, so I can easily go through it step by step in GHCi (with > indicating the prompt). We begin with a hole foo = _:
> foo :: a -> ((b -> a) -> c) -> c; foo = _
And we receive a message saying Found hole: _ :: a -> ((b -> a) -> c) -> c. GHC suggests foo :: a -> ((b -> a) -> c) -> c as a valid way of filling in the hole, and indeed foo = foo is legal, it’s just not the answer we’re looking for, since it represents an infinite loop.
Instead, we can look at the type and break it down into parts from the top down. We begin with a function type (->) whose input is a and whose output is ((b -> a) -> c) -> c. We can make a function value using a lambda expression, inventing a name for the a value, say x, and put another hole for the body:
> foo :: a -> ((b -> a) -> c) -> c; foo = \ x -> _
…
• Found hole: _ :: ((b -> a) -> c) -> c
…
It now mentions that we have x :: a available to work with, in addition to foo, but this isn’t quite enough, so next we can take apart ((b -> a) -> c) -> c into its input ((b -> a) -> c) and output c. (From now on, for brevity’s sake, I’ll also skip repeating the type signature of foo.)
> foo :: …; foo = \ x -> \ f -> _
…
• Found hole: _ :: c
…
We can’t take apart the type variable c any further, and we know we need to make a value of type c, so we can look at what we have available:
f :: (b -> a) -> c
x :: a
foo :: a -> ((b -> a) -> c) -> c
So our options are:
Recursively call foo
Call f
#1 would quickly put us back in the same situation we’re in, so #2 is all that’s left. f expects a value of type b -> a as an argument:
> foo :: …; foo = \ x -> \ f -> f _
…
• Found hole: _ :: b -> a
…
So again we can write a lambda:
> foo :: …; foo = \ x -> \ f -> f (\ y -> _)
…
• Found hole: _ :: a
…
The only way we can produce a value of the unknown type a is to use the value x :: a that we’ve been given, so the final result is this:
foo = \ x -> \ f -> f (\ y -> x)
And that can be written in exactly the same form as you put in your question, using a little syntactic sugar, and a couple different choices of variable names:
foo = \ x -> \ f -> f (\ y -> x)
foo x = \ f -> f (\ y -> x)
foo x f = f (\ y -> x)
foo x y = y (\ z -> x)
Question 1
foo :: a -> ((b -> a) -> c) -> c
says that foo has to take an a and a function with type (b -> a) -> c and somehow produce a c.
foo a function = c
where a::a and function::(b -> a) -> c
but where can we get the c from?
Good news: function makes cs for us.
Let's use that. function::(b->a) -> c so we can get a c if we give it a (b->a).
So we need to first make a helper function that takes bs and gives us as:
foo a function =
let helper b = a
That's fine! I already had an a so I could use that. We just need to hand function the helper we just made:
foo :: a -> ((b -> a) -> c) -> c
foo a function =
let helper b = a
in function helper
Now notice that helper ignores its input, so we could write
foo :: a -> ((b -> a) -> c) -> c
foo a function =
let helper _ = a
in function helper
And we can use lambda notation for helper:
foo :: a -> ((b -> a) -> c) -> c
foo a function =
let helper = \_ -> a
in function helper
But now we could just write (\_ -> a) instead of helper:
foo :: a -> ((b -> a) -> c) -> c
foo a function =
function (\_ -> a)
And finally, lets abbreviate function as f:
foo :: a -> ((b -> a) -> c) -> c
foo a f = f (\_ -> a)
Question 2
foo2 :: (a -> b) -> (c -> a) -> c -> b
OK, this time we need to make a b. We're given a c and a couple of functions for turning as into bs and cs into as:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2
make_b_from_a
make_a_from_c
c
= b
Well, the only thing that can give us a b is make_b_from_a:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2
make_b_from_a
make_a_from_c
c
= make_b_from_a a
but now we need an a, but we can use make_a_from_c for that, and we already have a c:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2
make_b_from_a
make_a_from_c
c
= make_b_from_a (make_a_from_c c)
Let's shorten the names. I'm going to call the (c->a) one f because we use it before the other one, which I'll call g:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2 g f c = g (f c)
We can take the last argument using a lambda:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2 g f = \c -> g (f c)

Yet another infinite type error

I'm trying to create a function that composes a function f with a function g that takes multiple arguments.
c :: (a -> b) -> (c -> a) -> c -> b
c x y z = x(y(z))
lift = c c
(lift $ lift $ lift ... c) creates the desired function:
*Main> (lift $ lift $ lift $ lift $ lift $ c) (\x -> x+2) (\x y z a b c -> x*y*z-(a*b*c)) 1 2 3 4 5 6
-112
However, when I attempt to define a function to produce a function that takes f, g, then n arguments (to save typing), the following error occurs:
cn 1 = c
cn k = lift (cn(k-1))
<interactive>:9:1: error:
* Occurs check: cannot construct the infinite type: a ~ c0 -> a
Expected type: t -> (a -> b) -> a -> b
Actual type: t -> (a -> b) -> (c0 -> a) -> c0 -> b
* Relevant bindings include
cn :: t -> (a -> b) -> a -> b (bound at <interactive>:9:1)
Why does this error occur, and how might I resolve it?
You cannot make polyvariadic functions in Haskell without typeclasses.
When you try to make a function that takes either one or two arguments, you try to make a function of type a -> b and a -> p -> b. Hence, the compiler must infer that the type b is equivalent to p -> b, so the type of the function becomes a -> p -> p -> p -> .... In other words, an infinite type.
A similar problem occurs when you try to make this function. The first line is fine:
cn 1 = c
This would imply something like cn :: Int -> (b -> c) -> (a -> b) -> a -> c. However, we now have a problem in the second line:
cn k = lift (cn (k-1))
Since we know that cn :: Int -> (b -> c) -> (a -> b) -> a -> c, we must infer that cn (k-1) :: (b -> c) -> (a -> b) -> a -> c. However, since lift :: (x -> y -> z) -> x -> (w -> y) -> w -> z, we see that the return value must be of type (b -> c) -> (w -> a -> b) -> w -> c, which clashes with the original type declaration.
TL;DR: you can't change the type of a Haskell function/value via values. This means you can't write polyvariadic functions without certain tricks.

What is the justification for the type of unfoldr in Haskell?

The example given in the documentation of unfoldr :: (b -> Maybe (a, b)) -> b -> [a]:
unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
can easily be written with a redundant pair:
unfoldr (\b -> if b == 1 then Nothing else Just (b-1, b-1)) 11
What does unfoldr need the pair (a,b) for? Why is its type not (a -> Maybe a) -> a -> [a]?
A function with type
(a -> Maybe a) -> a -> [a]
restricts the output list element type to be the same as the state which is threaded through the generation process. unfoldr is more general in that it allows an independent type of state to be used.
Leveraging a bit of theory, one can recover the types for folds/unfolds of a recursive type, including lists, understanding why they are what they are.
Let A be a fixed type. The type "list of As" satisfies the isomorphism
List ~~ Either () (A, List)
which can be read "a list value is either a special value (the empty list), or a value of type A followed by a list value".
In a more succinct notation we could write Either as an infix +:
List ~~ () + (A, List)
Now, if we let F b = () + (A, b), we have that
List ~~ F List
The above is a fixed point equation, which always arises when using recursive types. For any recursive type defined by T ~~ F T we can
derive the type of the related folds/unfolds (also known as cata/ana or induction/coinduction principles)
fold :: (F b -> b) -> T -> b
unfold :: (b -> F b) -> b -> T
In the case of lists, we then obtain
fold :: ((() + (A, b)) -> b) -> List -> b
unfoldr :: (b -> (() + (A, b))) -> b -> List
The unfold can also be rewritten noting that Maybe c ~~ () + c:
unfoldr :: (b -> Maybe (A, b)) -> b -> List
The fold can instead be rewritten using
((x + y) -> z) ~~ (x -> z, y -> z)
getting
foldr :: (() -> b, (A, b) -> b) -> List -> b
then, since () -> b ~~ b,
foldr :: (b, (A, b) -> b) -> List -> b
finally, since (x, y) -> z ~~ x -> y -> z (currying), we have
foldr :: b -> ((A, b) -> b) -> List -> b
and again:
foldr :: b -> (A -> b -> b) -> List -> b
and with a final flip x -> y -> z ~~ y -> x -> z:
foldr :: (A -> b -> b) -> b -> List -> b
How do those types follow from the (co)induction principles?
Domain theory states that least fixed points (F(T)=T) coincide with least
prefixed points (F(T)<=T), when F is monotonic over a certain poset.
The induction principle simple states that, if T is the least prefixed point, and F(U)<=U, then T<=U. (Proof. It is the least!. QED.)
In formulae,
(F(U) <= U) ==> (T <= U)
To deal with fixed points over types, we need to switch from posets to categories, which makes everything more complex. Very, very roughly, every <= is replaced with some morphism. For instance, F(U)<=U now means that there is some morphism F U -> U. "Monotonic F" means that F is a functor (since a<=b implying F(a)<=F(b) now becomes (a->b) implying F a -> F b). Prefixed points are F-algebras (F u -> u). "Least" becomes "initial". And so on.
Hence the type of fold: (implication is -> as well)
fold :: (F u -> u) -> (T -> u)
Unfold derives from the coinduction principle, which deals with greatest postfix points T (which become coalgebras)
(U <= F(U)) ==> (U <= T)

Haskell: Evaluating lambda expressions manually - determine general types

First of all, sorry if I'm not not posting this on the correct site since I'm not sure if it's more of a mathematical question than a programming one, but since I'm using this with Haskell and comparing the results with a Haskell interpreter, I just thought I'd ask it here.
So I'm basically trying to evaluate lambda expressions in Haskell and I'm doing it manually (in preparation for an exam, since I'll be forced to do it on paper). I'm given some expressions and I have to write down their general types after they're evaluated. To do so, I'm using an interpreter to get a somewhat correct answer.
In particular, I'm going to evaluate the following expressions:
t2 = ( \x y z -> y.x.y );
tx2 = (\x y z -> y.z.z);
tp2 = (\x -> \y -> (x.y.x));
td2 = (\x y z f -> y(z(z(f))));
tm2 = (\z -> \y -> \x -> z.y.x);
Since I don't 100% understand how to do this, I've devised a method. First, I create a template that somewhat resembles what the evaluated expression will look like. I.E. if part of the left-size ('lambda'd') variable is featured on the right side (as it's pretty much functional composition in every case), it's a function. If not, it's just a variable. Afterwards, I'm trying to fit the general types of the functions as best as I can and I'm getting some semi-right results, but I'm sure I'm still making some mistakes. Here's my whole evaluation process:
t2 = ( \x y z -> y.x.y );
(_ -> _) -> (_ -> _) -> c -> _ -> _
y(x(y))
assume:
y :: a -> b
x :: b -> a
result: (b -> a) -> (a -> b) -> c -> a -> b
interpreter: (a -> b) -> (b -> a) -> c -> b -> a
z isn't featured on the right side, so it's not a function in this case. I'm assigning it c. Now I'm looking at the composition on the right side. I'm going right to left and I assign a -> b to y since I have no idea about it's input or output. Since x uses the result of y as an input, and y uses x' output as an input again, x is b -> a. Which I can just insert into my template.
As you can see, it's not exactly the same result as I get via the interpreter, but it's only a and b being switched around, so it doesn't seem that wrong.
tx2 = (\x y z -> y.z.z);
a -> (_ -> _) -> (_ -> _) -> _ -> _
y(z(z))
assume:
z :: b -> b
y :: b -> c
result: a -> (b -> c) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
Same as above. Since z uses itself in functional composition, I assume it has the same input and output. y uses z's output as input and has some unknown output, hence c. This appears to be in line with my interpreter.
tp2 = (\x -> \y -> (x.y.x));
(_ -> _) -> (_ -> _) -> _ -> _
x(y(x))
assume:
x :: a -> b
y :: b -> a
result: (a -> b) -> (b -> a) -> a -> b
interpreter: (a -> b) -> (b -> a) -> a -> b
Pretty much the same as the first example, only I don't have an unused lambda variable.
td2 = (\x y z f -> y(z(z(f))));
a -> (_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _
y(z(z(f)))
assume:
f :: _ -> b
z :: b -> b
y :: b -> c
assume: a -> (b -> c) -> (b -> b) -> (_ -> b) -> b -> c
result: a -> (b -> c) -> (b -> b) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
Everything but x is a function in this case. f's Input isn't initially known to me and I'm just leaving it empty at the time. z uses f's output and it's own output in composition, so I just assign it b -> b. y uses z's output, and has an unknown output itself, so it gets b -> c.
Now I insert it into my template, but I'm still missing an input for f. Since there's a b right after f, I just assume it uses b as an input, too.
Now there's the first real question: where did f disappear to in the answer given by the interpreter? I can only assume since it uses the same input/output as z and it's basically in composition with it, it just got simplified into a single b->b, but I'm not sure about this.
tm2 = (\z -> \y -> \x -> z.y.x);
tm2 = (\z y x -> z.y.x);
(_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _
z(y(x))
assume:
x = a -> b
y = b -> _
z = _ -> _
assume: (_ -> _) -> (b -> _) -> (a -> b) -> _ -> _
result?: (a -> c) -> (b -> a) -> (a -> b) -> a -> c
interpreter: (a -> b) -> (c -> a) -> (d -> c) -> d -> b
Here's where it all falls apart: z, y, and x are functions. So I'm just assigning a -> b to x, which means that y's input is b. The output is unknown to me at this time. Same goes for z, since I have no idea about y's output.
So after I enter them in my template, the only thing that's really left for me is just to fill in the blanks for unknown values. Since x would require a as input, it means that there's an a right after it. Which would mean that it's z's input, too. Since it's z's input, I can assume it's y's output. The only thing left to fill in is z's output, and I just assign it a c since I don't really know what it could be.
As you can see, this isn't what the interpreter gives me, at all. While the left hand side might be still somewhat similar, I don't understand what happens on the right hand side, at all. Why is it d -> b? Shouldn't it be whatever's the result of (z(y(x))), which should have z's input/output?
Thanks in advance for any help you might offer me.
There are three basic properties you can exploit:
Due to currying, \x y -> z is equivalent to \x -> \y -> z.
For any x(y), you know that x must be a function and its first argument matches the type of the expression y.
You know the type of ., which is (b -> c) -> (a -> b) -> a -> c. Furthermore, . is right-associative (i.e. a.b.c is the same as a.(b.c)).
With this in mind, consider your first example:
t2 = ( \x y z -> y.x.y );
Clearly, it's a function of three arguments, so its type will be something akin to
t2 :: ty0 -> ty1 -> ty2 -> ty3
I use ty0 through ty3 here to denote the types to infer. ty0 is the type of the x argument, ty1 is for y, ty2 for z and ty3 is the type of the result value (i.e. the type of the expression y.x.y).
I'd start with determining the type ty3 (which is defined by the expression y.x.y) because while doing so you'll also find the types of the used arguments. Unused arguments can have any type:
y.x.y is equivalent to y.(x.y) (due to right-associativity of ., see item #3 above). So you can start by considering the subexpression x.y.
This means that x :: (b -> c) and y :: (a -> b) and hence x.y :: a -> c (due to the type of ., again see #3 above).
So we know that y :: (a -> b) and x.y :: a -> c. With this in mind, the only way y.(x.y) can type check (i.e. match the type of .) is when c ~ a, i.e. c and a are the same type.
Hence, x :: b -> a (our ty0!) and y :: a -> b (ty1) andy.(x.y) :: a -> b(what we calledty3` above). You can plug this into our primitive 'three-argument function type' above.
t2 :: ty0 -> ty1 -> ty2 -> ty3
=>
t2 :: (b -> a) -> (a -> b) -> ty2 -> (a -> b)
...and since -> is right-associative, you can omit the last parens (and instead of ty2 you could have used c, of course).
Let's try the same strategy on your last example:
tm2 = (\z -> \y -> \x -> z.y.x);
This is equivalent to \z y x -> z.y.x (due to currying, see #1 in the list at the top).
This means it's another three-argument function of the form tm2 :: ty0 -> ty1 -> ty2 -> ty3. Again, we start by inferring the type ty3 by considering the definition of the function.
The type ty3 is the type of the expression z.y.x, which is equivalent to z.(y.x) (due to right-associativity of .).
All three variables must be functions to satisfy the type of . (see #3 in the list at the top).
So x :: a -> b, y :: b -> c, y.x :: a -> c.
From this, it follows that z :: c -> d and hence z.y.x :: a -> d.
Since z is the first argument to tm2, y is the second and x is the third argument, you can tell that
tm2 :: (c -> d) -> (b -> c) -> (a -> b) -> (a -> d)

Resources