了解Y-Combinator的实现

时间:2018-11-27 02:31:34

标签: scala recursion functional-programming lambda-calculus y-combinator

我想详细了解一下我们如何从Y-combinator的lambda微积分表达式中得到:

Y = λf.(λx.f (x x)) (λx.f (x x))

到以下实现(在Scala中):

def Y[A, B](f: (A => B) => A => B): A => B = (x: A) => f(Y(f))(x)

我对函数式编程非常陌生,但是对lambda演算以及替换过程的工作方式有很好的了解。但是,我很难理解我们如何从形式表达到实现。

此外,我想知道如何分辨函数的自变量类型数量及其返回类型是什么 lambda

2 个答案:

答案 0 :(得分:5)

首先,Scala代码是很长的写法:

def Y[A, B](f: (A => B) => A => B): A => B = f(Y(f))

此处f被部分应用。 (看来代码作者选择使用lambda使其更加明确。)

现在,我们如何得出此代码? Wikipedia notes代表Y f = f (Y f)。将其扩展为类似于Scala的东西,我们有def Y(f) = f(Y(f))。在lambda演算中,这不能用作定义,它不允许直接递归,但在Scala中可以使用。为了使它成为有效的Scala,我们需要添加类型。将类型添加到f会导致:

def Y(f: (A => B) => A => B) = f(Y(f))

由于AB是免费的,因此我们需要使它们成为参数:

def Y[A, B](f: (A => B) => A => B) = f(Y(f))

由于它是递归的,因此我们需要添加一个返回类型:

def Y[A, B](f: (A => B) => A => B): A => B = f(Y(f))

答案 1 :(得分:3)

请注意,您编写的不是Y组合器的实现。 “ Y组合器”是λ微积分中的特定“定点组合器”。术语g的“定点”仅是点x,使得,

g(x) = x 

“定点组合器” F是可用于“产生”定点的术语。也就是说,

g(F(g)) = F(g)

术语Y = λf.(λx.f (x x)) (λx.f (x x))是遵循该等式的众多术语中的一个,即g(Y(g)) = Y(g)可以将一个术语简化为另一个术语。此属性表示可以使用这些术语(包括Y来对演算中的“递归”进行编码。

关于键入,请注意,Y组合器无法在简单键入的λ微积分中键入。甚至在系统F的多态演算中也没有。如果尝试键入它,则会得到“无限深度”的类型。要键入它,您需要在类型级别上递归。因此,如果您想扩展例如您只需将Y作为原始函数提供给一种小型函数式编程语言即可输入λ微积分。

虽然您没有使用λ微积分,但是您的语言已经附带了递归。因此,您在Scala中编写的是定点“组合器”的简单定义。直截了当,因为它是定点(几乎)紧随定义之后。

Y(f)(x) = f(Y(f))(x)

因此对于所有x都是正确的(并且它是一个纯函数),

Y(f) = f(Y(f))

是定点的等式。关于Y类型的推论,考虑方程Y(f)(x) = f(Y(f))(x)并让

f : A => B
Y : C => D 

因为Y : C => Df : A => B作为输入,所以

C = A => B

因为Y f : Df : A => B的输入,然后

D = A

,由于输出Y f : Df(Y(f)) : B相同,因此

D = B

到此为止,

Y : (A => A) => A 

由于Y(f)应用于xY(f)是一个函数,所以

A = A1 => B1 

对于某些类型A1B1,因此

Y : ((A1 => B1) => (A1 => B1)) => A1 => B1