关于Y组合子,网上已经介绍很多了,其作用主要是解决匿名lambda的递归调用自己。

首先我们来看直观的递归lambda定义,

假设要定义阶乘的lambda表达,C#中需要这么定义

Func<int, int> fact = null;
fact = x => x <= ? : x * fact(x - );

这种方法非常简单直接,当然问题也存在,因为这里fact其实是一个委托对象,当这个对象改变后,可能就得不到阶乘的效果了。

在scala中则是这样,

def F: Int => Int = (n:Int) => if(n == 0) 1 else  n* F(n - 1)

嗯,在本文的主打语言Racket中,则变成这样

(define F
(lambda (n) (if (equal? n ) (* n (F (- n ))))))

由于这个函数F定义中使用了F自身,那么如何修改可以去掉这个F?

现在变化一下,增加一个函数参数f,以使的我们调用F时,可以把自身传递进去,那样就解决了前面F的定义中使用了F自身的问题,修好后如下

(define FF
(lambda (f) (lambda (n) (if (equal? n ) (* n ((f f) (- n )))))))

这样调用((FF FF) 5)就能得到120这个结果了。

当然这里我们甚至可以不用define这个关键字来给这个lambda定义一个名字,直接上lambda本体,如下

(((lambda (f) (lambda (n) (if (equal? n )

                              (* n ((f f) (- n ))))))
(lambda (f) (lambda (n) (if (equal? n ) (* n ((f f) (- n ))))))) )

同意可以得到正确结果120。

上面这个方法算是比较直接,一个更加优雅的解决方法当然就是本文的主jiao:Y组合子

Y组合子

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

一种使用Racket的表示为

(define Y
(lambda (f) ((lambda (x) (f (lambda (y) ((x x) y))))
(lambda (x) (f (lambda (y) ((x x) y)))))))

这样,阶乘的lambda表示为

(define Fact
(Y (lambda (f) (lambda (n) (if (equal? n ) (* n (f (- n ))))))))

斐波那契的lambda表示为

(define Fib
(Y (lambda (f) (lambda (n) (if (< n ) (+ (f (- n )) (f (- n ))))))))

这里,关键点在于,Y的参数为一个函数,比如阶乘中是

(lambda (f) (lambda (n) (if (equal? n )

                                 (* n (f (- n ))))))

这个表达式中可以用f表示自身。

Racket中使用Y组合子的更多相关文章

  1. Lambda演算 - 简述Y组合子的作用

    Y组合子:\f.(\x.f(xx))(\x.f(xx)),接受一个函数,返回一个高阶函数 Y组合子用于生成匿名递归函数. 什么叫匿名递归函数,考虑以下C语言递归函数 int sum(int n) { ...

  2. 大到可以小说的Y组合子(一)

    问:上回乱扯淡了一通,这回该讲正题了吧. 答:OK. 先来列举一些我参考过,并从中受到启发的文章. (1.)老赵的一篇文章:使用Lambda表达式编写递归函数 (2.)装配脑袋的两篇文章:VS2008 ...

  3. 大到可以小说的Y组合子(三)

    答:关于Fix的问题你fix了吗? 问:慢着,让我想想,上次留下个什么问题来着?是说我们有了一个求不动点的函数Fix,但Fix却是显式递归的,是吧? 答:有劳你还记的这个问题. 问:Fix的参与背离了 ...

  4. 大到可以小说的Y组合子(零)

    问:啊!我想要一个匿名的递归… 答:Y(音同Why)… … … 问:作为一位命令式语言的使用者,为什么会突然折腾起Y组合子呢? 答:的确,这事儿要从很久以前的几次搁浅开始说起…上学的时候,从来没有接触 ...

  5. 简单易懂的程序语言入门小册子(4):基于文本替换的解释器,递归,如何构造递归函数,Y组合子

    递归.哦,递归. 递归在计算机科学中的重要性不言而喻. 递归就像女人,即令人烦恼,又无法抛弃. 先上个例子,这个例子里的函数double输入一个非负整数$n$,输出$2n$. \[ {double} ...

  6. Y组合子

    Y组合子 Y组合子的用处 作者:王霄池链接:https://www.zhihu.com/question/21099081/answer/18830200来源:知乎著作权归作者所有.商业转载请联系作者 ...

  7. 大到可以小说的Y组合子(二)

    问:上一回,你在最后曾提到"抽象性不足",这话怎么说? 答:试想,如果现在需要实现一个其它的递归(比如:Fibonacci),就必须把之前的模式从头套一遍,然后通过fib_make ...

  8. 用不动点组合子解递归(python实现)

    不动点组合子 Y = λf. (λx. f (x x)) (λx. f (x x)) θ = (λx. λy. (y(x x y))) (λx.λy.(y(x x y))) Y f = f (Y f) ...

  9. [学习] 从 函数式编程 到 lambda演算 到 函数的本质 到 组合子逻辑

    函数式编程 阮一峰 <函数式编程初探>,阮一峰是<黑客与画家>的译者. wiki <函数编程语言> 一本好书,<计算机程序的构造与解释>有讲到schem ...

随机推荐

  1. Hypeiron Planning/Essbase修改规划类型名称

    1.修改planning关系库 1.1--修改Plan_type,例如将type_name “Plan1”修改为”Plan1ts”,提交 SELECT * FROM hsp_plan_type FOR ...

  2. 阿里云WinServer2008下配置IIS7支持php

    先送一只法克鱿给百度,百度了n多的方法都或多或少有问题. 0.php安装包 php-5.2.1-Win32.zip 下载地址 http://pan.baidu.com/s/1pJuc8YZ 最开始是p ...

  3. 我看TDD测试驱动开发

    今天在实验室给大家介绍了一下TDD和Docker,大家对TDD都比较感兴趣,包括老板,也问了一些问题. 还是从头来说TDD吧,TDD作为敏捷开发领域的领头军,充满魅力,同时也充满争议.一切从三大军规说 ...

  4. 使用指定格式的字符串变量格式化日期字符串,DateAndTime取时间间隔

    private void btn_GetTime_Click(object sender, EventArgs e) { lab_time.Text = DateTime.Now.ToString(& ...

  5. 用Python复习离散数学(二)

    这次复习的是计数问题,立刻走起吧! 1.乘法原理 如果一项工作需要t步完成的,第一步有n1种不同的选择,第二步有n2种不同的选择,……,第t步有nt中不同的选择,那么完成这项工作所有可能的选择种数为: ...

  6. 在 Ubuntu 12.04 上通过 Tomcat 部署 Solr 4

    http://www.oschina.net/question/12_71342 可行

  7. seajs代码

    打包并压缩seajs代码 背景 seajs是一款优秀的模块开发插件,但是当我们使用它来进行模块化开发的时候,由于它的每个模块的加载都会进行一次http请求,那么当模块数量倍增的时候,会拖慢页面的加载速 ...

  8. Stream使用教程

    现在,计算机CPU运行速度的快速发展已经远远超过了内存的访问速度.越来越多的程序性能被内存带宽所限制,而不是计算机的CPU运行速率. Stream benchmark是一个简单的合成基准测试程序,衡量 ...

  9. CSS属性合写

    animation:[[ animation-name ] || [ animation-duration ] || [ animation-timing-function ] || [ animat ...

  10. LinqToXml高级用法介绍

    LinqToXml高级用法介绍 一.函数构造 什么是函数构造?其是指通过单个语句构建XML树的能力. 那么它有什么作用呢? 作用1.用单个表达式快速创建复杂的XML树 见实例代码CreateXml( ...