考虑这个组合子:
S (S K)
将其应用于参数X Y:
S (S K) X Y
它签约:
X Y
我将S(S K)转换为相应的Lambda术语并得到了这个结果:
(\x y -> x y)
我使用Haskell WinGHCi工具获取(\ x y - > x y)的类型签名并返回:
(t1 -> t) -> t1 -> t
这对我有意义。
接下来,我使用WinGHCi获取s(s k)的类型签名并返回:
((t -> t1) -> t) -> (t -> t1) -> t
这对我没有意义。为什么类型签名不同?
注意:我将s,k和i定义为:
s = (\f g x -> f x (g x))
k = (\a x -> a)
i = (\f -> f)
答案 0 :(得分:9)
我们从k
和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))
因此,将k
作为s
的第一个参数传递,我们将k
的类型与s
的第一个参数统一起来,然后使用{{1在类型
s
因此我们获得了
s :: (t1 -> t2 -> t1) -> (t1 -> t2) -> t1 -> t1
然后在s k :: (t1 -> t2) -> t1 -> t1
s k = (\g x -> k x (g x)) = (\g x -> x)
中,外部s (s k)
用于类型(s
,t3 = t1 -> t2
)
t4 = t5 = t1
将其应用于s :: ((t1 -> t2) -> t1 -> t1) -> ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
会删除第一个参数的类型并留下
s k
总结:在Haskell中,s (s k) :: ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
的类型来自其组成子表达式的类型,而不是它对其参数的影响。因此,它具有比表示s (s k)
的效果的lambda表达式更少的通用类型。
答案 1 :(得分:7)
您使用的类型系统与简单类型的lambda演算基本相同(您不使用任何递归函数或递归类型)。简单类型的lambda演算并不完全通用;它不是图灵完备的,它不能用于编写一般递归。 SKI组合子演算是图灵完备的,可用于编写定点组合器和一般递归;因此,SKI组合子微积分的全部功效不能用简单类型的lambda演算表示(尽管它可以是无类型的lambda演算)。
答案 2 :(得分:2)
感谢所有回答我问题的人。我研究了你的回答。为了确保我理解我所学到的知识,我已经为自己的问题写了自己的答案。如果我的回答不正确,请告诉我。
我们从k
和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))
让我们首先确定(s k)
的类型签名。
回顾s
的定义:
s = (\f g x -> f x (g x))
将k
替换为f
会导致(\f g x -> f x (g x))
签约:
(\g x -> k x (g x))
重要 g和x的类型必须与k
的类型签名一致。
回想一下k
有这种类型的签名:
k :: t1 -> t2 -> t1
因此,对于此函数定义k x (g x)
,我们可以推断:
x
的类型是k
的第一个参数的类型,类型为t1
。
k
的第二个参数的类型为t2
,因此(g x)
的结果必须为t2
。
g
已将x
作为其参数,我们已经确定其类型为t1
。因此(g x)
的类型签名为(t1 -> t2)
。
k
的结果类型为t1
,因此(s k)
的结果为t1
。
因此,(\g x -> k x (g x))
的类型签名就是:
(t1 -> t2) -> t1 -> t1
接下来,k
被定义为始终返回其第一个参数。所以这个:
k x (g x)
与此签订合同:
x
而且:
(\g x -> k x (g x))
与此签订合同:
(\g x -> x)
好的,现在我们已经找到了(s k)
:
s k :: (t1 -> t2) -> t1 -> t1
s k = (\g x -> x)
现在让我们确定s (s k)
的类型签名。
我们以同样的方式进行。
回顾s
的定义:
s = (\f g x -> f x (g x))
将(s k)
替换为f
会导致(\f g x -> f x (g x))
签约:
(\g x -> (s k) x (g x))
重要 g
和x
的类型必须与(s k)
的类型签名一致。
回想一下(s k)
有这种类型的签名:
s k :: (t1 -> t2) -> t1 -> t1
因此,对于此函数定义(s k) x (g x)
,我们可以推断:
x
的类型是(s k)
的第一个参数的类型,类型为(t1 -> t2)
。
(s k)
的第二个参数的类型为t1
,因此(g x)
的结果必须为t1
。
g
有x
作为参数,我们已经确定它的类型为(t1 -> t2)
。
因此(g x)
的类型签名为((t1 -> t2) -> t1)
。
(s k)
的结果类型为t1
,因此s (s k)
的结果为t1
。
因此,(\g x -> (s k) x (g x))
的类型签名就是:
((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
之前我们确定s k
有这个定义:
(\g x -> x)
也就是说,它是一个带有两个参数并返回第二个参数的函数。
因此,这个:
(s k) x (g x)
与此相符:
(g x)
而且:
(\g x -> (s k) x (g x))
与此签订合同:
(\g x -> g x)
好的,现在我们已经找到了s (s k)
。
s (s k) :: ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
s (s k) = (\g x -> g x)
最后,将s (s k)
的类型签名与此函数的类型签名进行比较:
p = (\g x -> g x)
p
的类型是:
p :: (t1 -> t) -> t1 -> t
p
和s (s k)
具有相同的定义(\g x -> g x)
,为什么他们有不同的类型签名?
s (s k)
的类型签名与p
不同的原因是p
没有约束。我们发现s
中的(s k)
被限制为与k
的类型签名一致,s
中的第一个s (s k)
被限制为一致类型签名为(s k)
。因此,s (s k)
的类型签名由于其参数而受到约束。即使p
和s (s k)
具有相同的定义,g
和x
上的约束也会有所不同。