我能够做简单的Lambda Calculus削减但是,我无法弄清楚如何做那些获得" currying" 。
这是我无法弄清楚的两个例子:
( ( ( lambda x . ( lambda y . ( j y ) ) ) j ) m )
( ( lambda p . ( p j ) ) ( lambda x . ( q x )))
答案 0 :(得分:2)
备注评估中出现错误,而是缩小为j m
,因此关于自我申请的部分并不相关。
Currying是一种观察,你可以用不同的方式查看一系列lambda抽象:
在数学术语中,( ( lambda x . ( lambda y . ( j y ) ) )
可以给出一个名称,然后写成:f(x,y) = j(y)
。在您的示例中,您将评估f(m,j) = j(j)
。那么,如果我们没有f的两个参数,会发生什么?我们无法完全评估它,但我们可以定义一个新函数g(y)= f(j,y),我们只需插入第一个参数。这种逐步的功能评估称为部分评估或currying。
在lambda演算中,这两个方面看起来完全相同。如果您想将两个历史记录应用于您的术语,请从第一个参数开始:
你的初始函数f(m,j):( ( ( lambda x . ( lambda y . ( j y ) ) ) j ) m )
简化为g(j):( ( lambda y . ( j y ) ) ) j
。当我们继续我们的评估时(我们仍然可以将我们的函数应用于j),我们得到j(j):j j
。现在我们不再应用任何约简规则,因此我们可以将j j
视为计算的结果。我们的结果是应用程序很好,但它应用于自身是一种特殊的东西。
(其余的与curry无关,而是与自我应用无关,这与@Matt写作的内容相连)
也许应该解释这意味着什么:函数j将自己作为参数。有了这个,你可以实现递归。着名的Y组合Y:(lambda x . f x x)
完全相同:如果您评估Y Y
,即(lambda x . f x x) Y
,则计算f (Y Y)
。再次评估内部Y Y
时,您计算f f (Y Y)
,依此类推。这正是函数f
的递归应用。副作用是对于某些f
,评估将永远不会终止(如果您使用标识函数(lambda x.x)
已经终止)。
20世纪中期的逻辑学家想要使用lambda-calculus作为数据结构,其中应该禁止无限的评估序列。限制lambda演算的一种可能性是你给每个变量一个类型(与编程语言中的类型非常相似)。如果要将变量应用于另一个变量,则需要适合这些类型。
E.g。假设x
的类型为int
,那么在应用程序f x
中,f
需要是一个类型,它采用int
类型的变量并计算结果,让我们说出string
类型。然后我们可以将f的类型写为int -> string
。 f x
的类型为string
,因为这是我们在x上评估f时得到的结果。
抽象创建了一个新功能。例如,(lambda x . x)
需要int
类型的参数,并生成int
类型的术语,即类型为int -> int
。
但现在像j j
这样的自我应用程序不再起作用了:比如内部j是t
类型。然后外部j必须是t -> t
类型。使这项工作的唯一方法是你的类型是t
的无限嵌套,这通常是被禁止的。
尽管这种方法看起来有点受限,但您可以在类型化的lambda演算之上添加递归来构建像Haskell或OCaml这样的编程语言。
答案 1 :(得分:1)
假设您正在使用价值评估策略调用简单类型的lambda演算,第一个减少喜欢这个:
x
代替j
y
代替m
通常没有将变量应用于变量的约简规则。这通常是我们使用类型系统的原因,以确保对于任何类型良好的程序,当我们评估时,我们永远不会被卡住"正如我们在第3步中所做的那样。
Currying不应该增加任何额外的复杂性,而不是你可能已经看到的。一般来说,策略形成e1 e2 ... en
形式的某种形式,您可以将其视为(((e1 e2) e3) ... en)
。然后你将减少e1 e2
,这应该产生一个lambda,你应该评估它应用于e3
,等等。
我会让你弄清楚第二个作为练习。