我想详细了解一下我们如何从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 ?
答案 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))
由于A
和B
是免费的,因此我们需要使它们成为参数:
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 => D
将f : A => B
作为输入,所以
C = A => B
因为Y f : D
是f : A => B
的输入,然后
D = A
,由于输出Y f : D
与f(Y(f)) : B
相同,因此
D = B
到此为止,
Y : (A => A) => A
由于Y(f)
应用于x
,Y(f)
是一个函数,所以
A = A1 => B1
对于某些类型A1
和B1
,因此
Y : ((A1 => B1) => (A1 => B1)) => A1 => B1