Consider this combinator:
S (S K)
Apply it to the arguments X Y:
S (S K) X Y
It contracts to:
X Y
I converted S (S K) to the corresponding Lambda terms and got this result:
(\x y -> x y)
I used the Haskell WinGHCi tool to get the type signature of (\x y -> x y) and it returned:
(t1 -> t) -> t1 -> t
That makes sense to me.
Next, I used WinGHCi to get the type signature of s (s k) and it returned:
((t -> t1) -> t) -> (t -> t1) -> t
That doesn’t make sense to me. Why are the type signatures different?
Note: I defined s, k, and i as:
s = (\f g x -> f x (g x))
k = (\a x -> a)
i = (\f -> f)
Thanks to all who responded to my question. I have studied your responses. To be sure that I understand what I’ve learned I have written my own answer to my question. If my answer is not correct, please let me know.
We start with the types of
kands:Let’s first work on determing the type signature of
(s k).Recall
s‘s definition:Substituting
kforfresults in(\f g x -> f x (g x))contracting to:Important The type of g and x must be consistent with
k‘s type signature.Recall that
khas this type signature:So, for this function definition
k x (g x)we can infer:The type of
xis the type ofk‘s first argument, which is the typet1.The type of
k‘s second argument ist2, so the result of(g x)must bet2.ghasxas its argument which we’ve already determined has typet1. So the type signature of(g x)is(t1 -> t2).The type of
k‘s result ist1, so the result of(s k)ist1.So, the type signature of
(\g x -> k x (g x))is this:Next,
kis defined to always return its first argument. So this:contracts to this:
And this:
contracts to this:
Okay, now we have figured out
(s k):Now let’s determine the type signature of
s (s k).We proceed in the same manner.
Recall
s‘s definition:Substituting
(s k)forfresults in(\f g x -> f x (g x))contracting to:Important The type of
gandxmust be consistent with(s k)‘s type signature.Recall that
(s k)has this type signature:So, for this function definition
(s k) x (g x)we can infer:The type of
xis the type of(s k)‘s first argument, which is the type(t1 -> t2).The type of
(s k)‘s second argument ist1, so the result of(g x)must bet1.ghasxas its argument, which we’ve already determined has type(t1 -> t2).So the type signature of
(g x)is((t1 -> t2) -> t1).The type of
(s k)‘s result ist1, so the result ofs (s k)ist1.So, the type signature of
(\g x -> (s k) x (g x))is this:Earlier we determined that
s khas this definition:That is, it is a function that takes two arguments and returns the second.
Therefore, this:
Contracts to this:
And this:
contracts to this:
Okay, now we have figured out
s (s k).Lastly, compare the type signature of
s (s k)with the type signature of this function:The type of
pis:pands (s k)have the same definition(\g x -> g x)so why do they have different type signatures?The reason that
s (s k)has a different type signature thanpis that there are no constraints onp. We saw that thesin(s k)is constrained to be consistent with the type signature ofk, and the firstsins (s k)is constrained to be consistent with the type signature of(s k). So, the type signature ofs (s k)is constrained due to its argument. Even thoughpands (s k)have the same definition the constraints ongandxdiffer.