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)
We start with the types of k and s
k :: t1 -> t2 -> t1
k = (\a x -> a)
s :: (t3 -> t4 -> t5) -> (t3 -> t4) -> t3 -> t5
s = (\f g x -> f x (g x))
So passing k as the first argument of s, we unify k's type with the type of s's first argument, and use s at the type
s :: (t1 -> t2 -> t1) -> (t1 -> t2) -> t1 -> t1
hence we obtain
s k :: (t1 -> t2) -> t1 -> t1
s k = (\g x -> k x (g x)) = (\g x -> x)
Then in s (s k), the outer s is used at the type (t3 = t1 -> t2, t4 = t5 = t1)
s :: ((t1 -> t2) -> t1 -> t1) -> ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
applying that to s k drops the type of the first argument and leaves us with
s (s k) :: ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
As a summary: In Haskell, the type of s (s k) is derived from the types of its constituent subexpressions, not from its effect on its argument(s). Therefore it has a less general type than the lambda expression that denotes the effect of s (s k).
The type system you are using is basically the same as simply-typed lambda calculus (you are not using any recursive functions or recursive types). Simply-typed lambda calculus is not fully general; it is not Turing-complete, and it cannot be used to write general recursion. SKI combinator calculus is Turing-complete, and can be used to write fixed-point combinators and general recursion; therefore, the full power of SKI combinator calculus cannot be expressed in simply-typed lambda calculus (although it can be in untyped lambda calculus).
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 k and s:
k :: t1 -> t2 -> t1
k = (\a x -> a)
s :: (t3 -> t4 -> t5) -> (t3 -> t4) -> t3 -> t5
s = (\f g x -> f x (g x))
Let's first work on determing the type signature of (s k).
Recall s's definition:
s = (\f g x -> f x (g x))
Substituting k for f results in (\f g x -> f x (g x)) contracting to:
(\g x -> k x (g x))
Important The type of g and x must be consistent with k's type signature.
Recall that k has this type signature:
k :: t1 -> t2 -> t1
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:
(t1 -> t2) -> t1 -> t1
Next, k is defined to always return its first argument. So this:
k x (g x)
contracts to this:
x
And this:
(\g x -> k x (g x))
contracts to this:
(\g x -> x)
Okay, now we have figured out (s k):
s k :: (t1 -> t2) -> t1 -> t1
s k = (\g x -> x)
Now let's determine the type signature of s (s k).
We proceed in the same manner.
Recall s's definition:
s = (\f g x -> f x (g x))
Substituting (s k) for f results in (\f g x -> f x (g x)) contracting to:
(\g x -> (s k) x (g x))
Important The type of g and x must be consistent with (s k)'s type signature.
Recall that (s k) has this type signature:
s k :: (t1 -> t2) -> t1 -> t1
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:
((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
Earlier we determined that s k has this definition:
(\g x -> x)
That is, it is a function that takes two arguments and returns the second.
Therefore, this:
(s k) x (g x)
Contracts to this:
(g x)
And this:
(\g x -> (s k) x (g x))
contracts to this:
(\g x -> g x)
Okay, now we have figured out s (s k).
s (s k) :: ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
s (s k) = (\g x -> g x)
Lastly, compare the type signature of s (s k) with the type signature of this function:
p = (\g x -> g x)
The type of p is:
p :: (t1 -> t) -> t1 -> t
p and s (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 than p is that there are no constraints on p. We saw that the s in (s k) is constrained to be consistent with the type signature of k, and the first s in s (s k) is constrained to be consistent with the type signature of (s k). So, the type signature of s (s k) is constrained due to its argument. Even though p and s (s k) have the same definition the constraints on g and x differ.
来源:https://stackoverflow.com/questions/9592191/the-type-signature-of-a-combinator-does-not-match-the-type-signature-of-its-equi