【专栏】康托尔、哥德尔、图灵——永恒的金色对角线(7)

Y是一个lambda函数,它接受一个伪递归F,在内部生成一个f_gen,然后把f_gen应用到它自身(记得power_gen(power_gen)吧),得到的这个f_gen(f_gen)也就是F的不动点了(因为f_gen(f_gen) = F(f_gen(f_gen))),而根据不动点的性质,F的不动点也就是那个对应于F的真正的递归函数!

铸造Y Combinator

现在我们终于可以铸造我们的Y Combinator了,Y Combinator只要生成一个形如power_gen的lambda函数然后把它应用到自身,就大功告成:

let Y = lambda F.

let f_gen = lambda self. F(self(self))

return f_gen(f_gen)

稍微解释一下,Y是一个lambda函数,它接受一个伪递归F,在内部生成一个f_gen(还记得我们刚才看到的power_gen吧),然后把f_gen应用到它自身(记得power_gen(power_gen)吧),得到的这个f_gen(f_gen)也就是F的不动点了(因为f_gen(f_gen) = F(f_gen(f_gen))),而根据不动点的性质,F的不动点也就是那个对应于F的真正的递归函数!

作者:刘未鹏 出版:电子工业出版社

如果你还觉得不相信,我们稍微展开一下看看,还是拿阶乘函数说事,首先我们定义阶乘函数的伪递归版本:

let Pwr = lambda self n. If_Else n==0 1 n*self(n-1)

让我们把这个Pwr交给Y,看会发生什么(根据刚才Y的定义展开吧):

Y(Pwr) =>

let f_gen = lambda self. Pwr(self(self))

return f_gen(f_gen)

Y(Pwr)的求值结果就是里面返回的那个f_gen(f_gen),我们再根据f_gen的定义展开f_gen(f_gen),得到:

Pwr(f_gen(f_gen))

也就是说:

Y(Pwr) => f_gen(f_gen) => Pwr(f_gen(f_gen))

我们来看看得到的这个Pwr(f_gen(f_gen))到底是不是真有递归的魔力。我们展开它(注意,因为Pwr需要两个参数,而我们这里只给出了一个,所以Pwr(f_gen(f_gen))得到的是一个单参(即n)的函数):

Pwr(f_gen(f_gen)) => If_Else n==0 1 n*f_gen(f_gen) (n-1)

而里面的那个f_gen(f_gen),根据f_gen的定义,又会展开为Pwr(f_gen(f_gen)),所以:

Pwr(f_gen(f_gen)) => If_Else n==0 1 n* Pwr(f_gen(f_gen)) (n-1) 

看到加粗的部分了吗?因为Pwr(f_gen(f_gen))是一个接受n为参数的函数,所以不妨把它令成f(f的参数是n),这样上面的式子就是:

f => If_Else n==0 1 n*f(n-1)

完美的阶乘函数!

(待续;此文的修订版已收录《暗时间》一书,由电子工业出版社2011年8月出版。作者于2009年7月获得南京大学计算机系硕士学位,现在微软亚洲研究院创新工程中心从事软件研发工程师工作。)

网络编辑:谢小跳

{{ isview_popup.firstLine }}{{ isview_popup.highlight }}

{{ isview_popup.secondLine }}

{{ isview_popup.buttonText }}