大到可以小说的Y组合子(三)
2015-02-10 01:12
162 查看
答:关于Fix的问题你fix了吗?
问:慢着,让我想想,上次留下个什么问题来着?是说我们有了一个求不动点的函数Fix,但Fix却是显式递归的,是吧?
答:有劳你还记的这个问题。
问:Fix的参与背离了匿名递归的定义,所以…所以…我们被Fix给坑了?
答:当然不是。你还记的第(一)章我们讨论过什么吗?
问:记的,我们把一个显式递归的Fact变成了一个匿名递归的结构。
答:很好,让我们再造一次轮子。
问:哦!我明白了,是用与上次类似的方法,把Fix写成一个匿名递归的Lambda。
答:就是这个意思,如此便可用这个Lambda来获得不动点了。那就动手吧,让我们一路与Fact对比:
观察最后产生的Fix,发现我们已经摆脱了显式的递归调用,且得到了一个可复用的不动点“生成器”。这里插一句题外话,我之前按照上述思路得到了Fix,后来才发现,原来这就是阿兰•图灵当年发现的Θ组合子(当然,我得到这个组合子要容易得多,因为图灵的年代根本没有计算机,更别说程序语言了)。我相信这两个组合子是完全等价的,下一章我们将以非形式化的方法来理解这一点。
问:那么,是时候揭开Y组合子的面纱了吧。
答:让子弹再飞一会儿。在此之前,“插播”一个小问题:如果递归函数的输入参数不止一个,该怎么办呢?例如用辗转相除法求最大公约数:
问:让我想想…嗯…那就要对之前定义的Y<T,TResult>做一些改变,写成这样:
然后,对之前的Fix改写成这样:
如此便可用这个Fix得到gcd_seed的不动点,即GCD递归函数:
答:很好,这是一个方案,但不是一个通用方案。如果有三个输入参数的递归呢?四个呢?…
问:难道还有更好的方法吗?
答:是的,答案就是Currying(柯里化)。所谓柯里化,就是把接受多个参数的函数变换成接受单一参数的函数,并且返回以柯里化的形式接受剩余参数,最终返回结果的一种技术。(注:我是在独立想到解决方案之后,才知道Currying的存在的哦!)
问:这…讲得有点抽象…
答:那就直接上例子吧。在上述最大公约数的例子中,把GCD柯里化成如下形式:
即:高阶函数GCD以m为参数,返回一个能与m求最大公约数的函数,这个函数再受一个参数n,便可返回(m,n)的最大公约数。同时,Y<T, TResult>和Fix无需任何改变,即可完成有两个输入参数的递归:
依此看来,两个参数的Y<T, TResult>就足以满足任何递归的需求了,美哉!
问:然是美哉!
答:就在下章,静候Y组合子的“粉墨登场”。待续…
问:慢着,让我想想,上次留下个什么问题来着?是说我们有了一个求不动点的函数Fix,但Fix却是显式递归的,是吧?
答:有劳你还记的这个问题。
问:Fix的参与背离了匿名递归的定义,所以…所以…我们被Fix给坑了?
答:当然不是。你还记的第(一)章我们讨论过什么吗?
问:记的,我们把一个显式递归的Fact变成了一个匿名递归的结构。
答:很好,让我们再造一次轮子。
问:哦!我明白了,是用与上次类似的方法,把Fix写成一个匿名递归的Lambda。
答:就是这个意思,如此便可用这个Lambda来获得不动点了。那就动手吧,让我们一路与Fact对比:
//C# //Func3 Fix = f=>f(Fix(x=>f(x))) //写成函数的形式为: Func1 Fix(Func2 f) { return (Func1)(f(x =>Fix(f)(x))); } //对比Fact int Fact(int x) { return x == 0 ? 1 : x * Fact(x - 1); }
//C# //为了把自己传给自己构造fix_maker OuroborosFunc<Func3> fix_maker = self => f => f(x => self(self)(f)(x)); //对比fact_maker OuroborosFunc<Func<int, int>> fact_maker = self => x => x == 0 ? 1 : x * self(self)(x - 1);
//C# //自我调用产生Fix Func3 Fix = ((Func<OuroborosFunc<Func3>, Func3>)(s => s(s))) (self => f => f(x => self(self)(f)(x))); //对比自我调用产生的Fact Func<int, int> Fact = ((Func<OuroborosFunc<Func<int, int>>, Func<int, int>>)(s => s(s))) (self => x => x == 0 ? 1 : x * self(self)(x - 1));
观察最后产生的Fix,发现我们已经摆脱了显式的递归调用,且得到了一个可复用的不动点“生成器”。这里插一句题外话,我之前按照上述思路得到了Fix,后来才发现,原来这就是阿兰•图灵当年发现的Θ组合子(当然,我得到这个组合子要容易得多,因为图灵的年代根本没有计算机,更别说程序语言了)。我相信这两个组合子是完全等价的,下一章我们将以非形式化的方法来理解这一点。
问:那么,是时候揭开Y组合子的面纱了吧。
答:让子弹再飞一会儿。在此之前,“插播”一个小问题:如果递归函数的输入参数不止一个,该怎么办呢?例如用辗转相除法求最大公约数:
//C# //GCD的显式递归 int GCD(int m, int n) { return n == 0 ? m : GCD(n, m % n); }
问:让我想想…嗯…那就要对之前定义的Y<T,TResult>做一些改变,写成这样:
//C# class Y<T1, T2, TResult> { public delegate TResult Func1(T1 p1, T2 p2); public delegate Func1 Func2(Func1 f1); public delegate Func1 Func3(Func2 f2); ... ... }
然后,对之前的Fix改写成这样:
//C# Func3 Fix = ((Func<OuroborosFunc<Func3>, Func3>)(s => s(s))) (self => f => f((x, y) => self(self)(f)(x, y)));
如此便可用这个Fix得到gcd_seed的不动点,即GCD递归函数:
//C# Y<int, int, int>.Func2 gcd_seed = gcd => (m, n) => n == 0 ? m : gcd(n, m % n); Console.WriteLine(Y<int, int, int>.Fix(gcd_seed)(24, 15)); //3
答:很好,这是一个方案,但不是一个通用方案。如果有三个输入参数的递归呢?四个呢?…
问:难道还有更好的方法吗?
答:是的,答案就是Currying(柯里化)。所谓柯里化,就是把接受多个参数的函数变换成接受单一参数的函数,并且返回以柯里化的形式接受剩余参数,最终返回结果的一种技术。(注:我是在独立想到解决方案之后,才知道Currying的存在的哦!)
问:这…讲得有点抽象…
答:那就直接上例子吧。在上述最大公约数的例子中,把GCD柯里化成如下形式:
//C# Func<int, int> GCD(int m) { return n => n == 0 ? m : GCD(n)(m % n); }
即:高阶函数GCD以m为参数,返回一个能与m求最大公约数的函数,这个函数再受一个参数n,便可返回(m,n)的最大公约数。同时,Y<T, TResult>和Fix无需任何改变,即可完成有两个输入参数的递归:
//C# Y<int, Func<int, int>>.Func2 gcd_seed = gcd => m => n => n == 0 ? m : gcd(n)(m % n); Console.WriteLine(Y<int, Func<int, int>>.Fix(gcd_seed)(24)(15)); //3
依此看来,两个参数的Y<T, TResult>就足以满足任何递归的需求了,美哉!
问:然是美哉!
答:就在下章,静候Y组合子的“粉墨登场”。待续…
相关文章推荐
- 大到可以小说的Y组合子(零)
- 大到可以小说的Y组合子(一)
- 大到可以小说的Y组合子(二)
- 角摩手机电子书生成专家 V2.1发布,可以合并txt,umd小说
- IP概念盛行的背后:资本在狂欢,电影想哭泣 IP,英文“Intellectual Property”的缩写,直译为“知识产权”。它的存在方式很多元,可以是一个故事,也可以是某一个形象,运营成功的IP可以在漫画、小说、电影、玩具、手游等不同的媒介形式中转换。
- 4个功能强大的国产APP,第2个可以免费看小说哦!
- 今天买了4本VC的书,过段时间就可以看新的“小说”了,呵呵
- 白领读小说 版本1.0 D盘自己放XXX.TXT 就可以
- [导入]新近上线了一个小说索引站点,喜欢看小说的同志们可以试用下
- 现在可以在微博上连载小说了
- 对生活迷茫时,可以看的小说..
- 终于可以好好开始写小说了
- java的小说展示,下载在查看所有(文件路径找不到,可以修改)
- 可以查看pdf格式小说阅读软件
- “道”无处不在—少林寺系列的衍生,神鬼类小说的哲学意义也是可以有的
- 没有什么不可以_零点
- 最近由于要用到分隔条,找到了一篇讲原理的, 实现了一个。可以双击缩到左边,可以左右拖动
- 一个漂亮的虚拟仪表控件,做UI喜欢UI的朋友可以进来看看 :-) ( BeauGauge Suite V2 )
- 什么头文件可以放在StdAfx.h
- java的System.getProperty()方法可以获取的值