Y组合子

// Y组合子
fact = n => n == 1 ? 1 : n * fact(n - 1)
// 无法匿名调用
(n => n == 1 ? 1 : n * fact(n - 1))(5)
// 参数可以命名, 消灭掉里面掉fact
fact = (f, n) => n == 1 ? 1 : n * f(f, n - 1);
// 只能有一个参数
fact = f => n => n == 1 ? 1 : n * f(f)(n - 1);
// 将fact带入 amazing!!! ??????
(f => n => n == 1 ? 1 : n * f(f)(n - 1))(f => n => n == 1 ? 1 : n * f(f)(n - 1))(5);
// f(f):2                   ----                                    ----        ^^^
// fact(fact):1

// 开始抽象
fact = f => n => n == 1 ? 1 : n * f(f)(n - 1);
// 先让匿名函数调用自己,把自己传进去,缓存自己,然后将执行函数返回
w = f => f(f)
// 将fact进行自我缓存,将执行函数暴露出来
w(fact)(5)
// 去掉变量的版本
w(f => n => n == 1 ? 1 : n * f(f)(n-1)) (5) // longer version
// f(f) 将他从内部系统中解耦出来
f => n => n == 1 ? 1 : n * f(f)(n - 1);
// 令g = f(f), 把f(f)的自调用,抽离出业务逻辑,以参数的形式传入
f => (g => n => n == 1 ? 1 : n * g(n - 1))( f(f) )
// eta规约 两个lamda算子若对于相同的输入产生相同的输出,则认为它们外延相等,可以互相规约
// eta规约 lamda x.f x ===  f
// js eta规约  x => f(x) === f(x)
// 实战 f(f)() === v => f(f)(v)
f => (g => n => n == 1 ? 1 : n * g(n - 1))( v => ( f(f)(v) ) )
// 将阶乘函数提取出来(g => n => n == 1 ? 1 : n * g(n - 1)),将之命名为fact0
( fact0 => f => fact0( v => ( f(f)(v) ) )( g => n => n == 1 ? 1 : n * g(n - 1) )
// 将之前的w代入
w(
    ( fact0 => f => fact0( v => ( f(f)(v) ) )( g => n => n == 1 ? 1 : n * g(n - 1) )
)(5)
// 把fact0解耦出来
( h => w(s => f => s( v => ( f(f)(v) )))(h))( g => n => n == 1 ? 1 : n * g(n - 1))
// Y组合子
( h => w(s => f => s( v => ( f(f)(v) )))(h) )
// 化简
( h => w(f => h( v => ( f(f)(v) ))) )
// 去掉w,最终Y组合子
(h =>
    (f => h ( v => f(f)(v) ))
    (f => h ( v => f(f)(v) ))
)

原文地址:https://www.cnblogs.com/pluslius/p/12384805.html

时间: 2024-08-01 13:26:56

Y组合子的相关文章

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

问:上回乱扯淡了一通,这回该讲正题了吧. 答:OK. 先来列举一些我参考过,并从中受到启发的文章. (1.)老赵的一篇文章:使用Lambda表达式编写递归函数 (2.)装配脑袋的两篇文章:VS2008亮点:用Lambda表达式进行函数式编程和用Lambda表达式进行函数式编程(续):用C#实现Y组合子 (3.)Y组合子的推导过程(用Scheme推导),这里的"推导"并不是数学意义上上的推导证明,而是说如何一步步引导构想出Y来的,值得一看.也许从某种程度反应出了当年Y是如何被发明的. [

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

Y组合子:\f.(\x.f(xx))(\x.f(xx)),接受一个函数,返回一个高阶函数 Y组合子用于生成匿名递归函数. 什么叫匿名递归函数,考虑以下C语言递归函数 int sum(int n) { return n == 0 ? 0 : n + sum(n-1); } 这个函数在内部递归调用了自身,调用自身需要函数本体的名字,这个函数叫sum,sum内部用名字sum,递归调用了自己 在lambda演算中,可以写成类似的表达式sum = \x. x == 0 ? 0 : sum x 但是对于一个

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

问:上一回,你在最后曾提到"抽象性不足",这话怎么说?  答:试想,如果现在需要实现一个其它的递归(比如:Fibonacci),就必须把之前的模式从头套一遍,然后通过fib_maker(fib_maker)来返回一个fib函数.可见,这个产生递归过程的"接口"让用户相当不舒服.  问:嗯,fib_maker(fib_maker)这种形式看起来的确不怎么舒服,那又如何对其进行抽象,以得到更好的接口呢?  答:这里,有两条路可以走.其一,就是对fact_maker(fa

重新发明 Y 组合子:不用 λ演算那一套

重新发明 Y 组合子:不用 λ演算那一套 重新发明 Y 组合子:不用 λ演算那一套 目录 1. 一类奇妙的函数 1.1. 三个例子 1.2. 构造方法 1.3. 程序分解 2. X 组合子 3. Y 组合子 4. 结语 1 一类奇妙的函数 1.1 三个例子 函数 (lambda ($) (lambda (n) (if (< n 2) 1 (* n (($ $) (- n 1)))))) 以一个函数为参数,当这个参数是函数本身时,返回计算阶乘的函数 函数 (lambda ($) (lambda (

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

答:关于Fix的问题你fix了吗? 问:慢着,让我想想,上次留下个什么问题来着?是说我们有了一个求不动点的函数Fix,但Fix却是显式递归的,是吧? 答:有劳你还记的这个问题. 问:Fix的参与背离了匿名递归的定义,所以-所以-我们被Fix给坑了? 答:当然不是.你还记的第(一)章我们讨论过什么吗? 问:记的,我们把一个显式递归的Fact变成了一个匿名递归的结构. 答:很好,让我们再造一次轮子. 问:哦!我明白了,是用与上次类似的方法,把Fix写成一个匿名递归的Lambda. 答:就是这个意思,

Racket中使用Y组合子

关于Y组合子,网上已经介绍很多了,其作用主要是解决匿名lambda的递归调用自己. 首先我们来看直观的递归lambda定义, 假设要定义阶乘的lambda表达,C#中需要这么定义 Func<int, int> fact = null; fact = x => x <= 1 ? 1 : x * fact(x - 1); 这种方法非常简单直接,当然问题也存在,因为这里fact其实是一个委托对象,当这个对象改变后,可能就得不到阶乘的效果了. 在scala中则是这样, def F: Int

scheme实现匿名递归阶乘(Y组合子)

(((lambda ()         ((lambda (f)        (f f))      (lambda (x)        ((lambda (y)           (lambda (n)             (if (zero? n)                 1                 (* n (y (- n 1)))))) (lambda z                                        (apply (x x) 

利用F#编写、理解Y组合子函数

赵劼的博客<使用Lambda表达式编写递归函数>中用C#实现了为函数求出 Y 组合子的函数.C#代码生涩,难以阅读,原代码如下: static Func<T, TResult> Fix<T,TResult>(Func<Func<T, TResult>, Func<T, TResult>> f) { return x => f(Fix(f))(x); } static Func<T1, T2, TResult> Fix

解析器组合子

本文引自:http://www.ibm.com/developerworks/cn/java/j-lo-compose/ Ward Cunningham 曾经说过,干净的代码清晰地表达了代码编写者所想要表达的东西,而优美的代码则更进一步,优美的代码看起来就像是专门为了要解决的问题而存在的.在本文中,我们将展示一个组合式解析器的设计.实现过程,最终的代码是优美的,极具扩展性,就像是为了解析特定的语法而存在的.我们还会选取 H.248 协议中的一个例子,用上述的组合式解析器实现其语法解析器.读者在这