首页 > 其他分享 >a little schemer chapter 9 Y组合算子

a little schemer chapter 9 Y组合算子

时间:2023-04-27 15:46:42浏览次数:51  
标签:chapter little 函数 factorial schemer else cond 表达式 lambda

内容参照

相关阅读推荐

 

首先是递归获得阶乘的例子

(define f
    (lambda (x) 
        (cond ((= x 1) 1)
            (else (* x (f (- x 1)))))))

对应的lambda (f):

(lambda (f) 
    (lambda (x) 
        (cond ((= x 1) 1)
            (else (* x (f (- x 1)))))))

但是参数是f,即是一个函数,所以要使得这段代码能够运行,应该传入一个函数。(ps:基础lambda表达式相关知识

1 ;factorial2
2 ((lambda (f) 
3     (lambda (x) 
4         (cond ((= x 1) 1)
5             (else (* x (f (- x 1)))))))            
6     (lambda (x) 
7         (cond ((= x 1) 1)
8             (else (* x (f (- x 1))))))2)

最后传入的参数是2

这段代码中,最外层的括号包含了一个函数调用 (lambda (x) ... ) 2),其中 2 是函数调用的参数。这个函数调用的参数是一个整数 2,它会被传递给内部的匿名函数。

内部的 lambda 表达式定义了一个函数,它接受一个参数 x,根据 x 是否等于 1 来返回不同的结果。如果 x 等于 1,则返回 1;否则返回 x 乘以 (f (- x 1)) 的结果,其中 f 是递归调用的函数。

在这个 lambda 表达式之前,有另一个 (lambda (f) ...) 表达式。这个表达式定义了一个函数 f,它接受一个参数 x,并根据 x 是否等于 1 来返回不同的结果。如果 x 等于 1,则返回 1;否则返回 x 乘以 (f (- x 1)) 的结果。这里的 (f (- x 1)) 表示递归调用,也就是调用函数 f 并传入参数 x-1

(lambda (f) ...) 表达式内部定义的函数 f 就是前面内部的 lambda 表达式中提到的那个递归调用的函数。这里使用了一个技巧,将函数 f 作为参数传递给自身。这样,当我们在函数中调用 f 时,实际上就是在调用自身。

最终,这段代码的结果是计算 2! 的值,即 2 乘以 1,等于 2。这里使用了递归实现阶乘函数,而且没有出现栈溢出的问题。

 

最开始代入的 lambda(x) 是第一行的 (lambda (f) ...) 中的 (lambda (x) ...) 表达式。因为整个表达式是一个函数应用,即 (f f),其中 (lambda (f) ...) 是被应用的函数,而 (lambda (x) ...) 是该函数的参数。

即此时第5行中的 f 函数是6-8 行的lambda 函数.

当代入3的时候,第8 行的 f 就没有定义了,出现错误,所以只能运行1-2的数值。

 

要改变这一状况,可以更改6-8行

 1 ;factorial3
 2 ((lambda (f) 
 3     (lambda (x) 
 4         (cond ((= x 1) 1)
 5             (else (* x (f (- x 1)))))))            
 6     ((lambda (f) 
 7         (lambda (x) 
 8             (cond ((= x 1) 1)
 9                 (else (* x (f (- x 1)))))))            
10         (lambda (x) 
11             (cond ((= x 1) 1)
12                 (else (* x (f (- x 1))))))))

这个时候就可以计算3的阶乘了。

我们观察上述式子可以发现,程序会在x == 1时停止,x != 1时会继续运行。我们可以让程序在 x != 1时生成(lambda (f) ....)。

1 ((lambda (f) 
2     (lambda (x) 
3         (cond ((= x 1) 1)
4             (else (* x ((f f) (- x 1)))))))
5     (lambda (f) 
6         (lambda (x) 
7             (cond ((= x 1) 1)
8                 (else (* x ((f f) (- x 1))))))))

 第4行中的两个 f 都是一样的,都是5-8行的那个表达式只不过这样子就可以无限调用了。

现在我们分析这个表达式,我们试着传2进去,去掉多余的式子,保留else,并展开(f f),得到

1 (* 2 (((lambda (f) 
2             (lambda (x) 
3                 (cond ((= x 1) 1)
4                     (else (* x ((f f) (- x 1)))))))
5             (lambda (f) 
6                 (lambda (x) 
7                     (cond ((= x 1) 1)
8                         (else (* x ((f f) (- x 1)))))))) 1))

我们可以看到,当x != 1时先执行(f f)生成了(F F),然后当x == 1时就不再执行(f f),程序停止。

  继续化简
1 ((lambda (f) (f f))
2     (lambda (f) 
3         (lambda (x) 
4             (cond ((= x 1) 1)
5                 (else (* x ((f f) (- x 1))))))))

第一行其实就是一段完整的代码,只是缩进有问题。

2-5行就是传入的参数

然后我们把else中的(f f)抽取出来,作为参数传递进去。

 1 ((lambda (f) (f f)) 
 2     (lambda (f)
 3         (
 4          (lambda (factorial) 
 5             (lambda (x) 
 6                 (cond ((= x 1) 1)
 7                     (else (* x (factorial (- x 1)))))))
 8           (f f)
 9          )
10       )
11  )

现在我们似乎只要把(lambda (factorial) ...)取出,作为参数传递进去,就能得到一个更加通用的不用函数名就能实现递归的方法了。

但是这个表达式是错的,因为最后一行的(f f)会在传递进factorial之前运行,由于(f f)里还有(f f),最终递归无法停止。我们得让(f f)不能先于factorial运行。

我们可以把最后一行(f f)变成lambda表达式

1 ((lambda (f) (f f)) 
2     (lambda (f)
3         ((lambda (factorial) 
4             (lambda (x) 
5                 (cond ((= x 1) 1)
6                     (else (* x (factorial (- x 1))))))) (lambda (x) ((f f) x)))))

现在我们可以把(lambda (factorial) ...)提取出来了。

1 (lambda (target) 
2     ((lambda (f) (f f))
3         (lambda (f) 
4             (target 
5                 (lambda (x) ((f f) x))))))
1 (((lambda (target) 
2     ((lambda (f) (f f))
3         (lambda (f) 
4             (target 
5                 (lambda (x) ((f f) x)))))) 
6     (lambda (factorial) 
7             (lambda (x) 
8                 (cond ((= x 1) 1)
9                     (else (* x (factorial (- x 1)))))))) 6)

这就是Y组合子

;Y Combinator
(define Y
    (lambda (target) 
        ((lambda (f) (f f))
            (lambda (f) 
                (target 
                    (lambda (x) ((f f) x)))))))

我们现在可以用Y组合子实现其它的匿名调用递归函数

;累加
(Y (lambda (acc) 
    (lambda (x) 
        (cond ((= x 0) 0)
            (else (+ x (acc (- x 1))))))))
;计算list的长度
(Y (lambda (length) 
        (lambda (l) 
            (cond ((null? l) 0)
                (else (+ 1 (length (cdr l))))))))

 

标签:chapter,little,函数,factorial,schemer,else,cond,表达式,lambda
From: https://www.cnblogs.com/xuenima/p/17358456.html

相关文章

  • Chapter4 朴素贝叶斯案例
    朴素贝叶斯案例:过滤垃圾邮件1.案例的流程示例:使用朴素贝叶斯对电子邮件进行分类(1)收集数据:提供文本文件。(2)准备数据:将文本文件解析成词条向量。(3)分析数据:检查词条确保解析的正确性。(4)训练算法:使用我们之前建立的trainNB0()函数。(5)测试算法:使用c......
  • Numerical Approximation Chapter 6 Notes
    Weierstrasstheoremapproximation之间也有高低,所以我们在compactsubset里面会有bestapproximation.但是以polynomialinterpolation为例,随着不断选更多的Chebyshevinterpolationpoints,对应的插值多项式次数越来越高的同时也会在插值点以外的地方越来越靠近函数本身。这种情......
  • Serre算术教程Chapter 5笔记
    二次型的范畴论定义考虑这样一个范畴\(S_n\),由一些freeabeliangroupofrank\(n\)\(E\)组成Definitionoffreeabeliangroup一个有basis的abeliangroup.这里basis就是那个基的意思,everyelementcouldbeuniquelyexpressedasanlinearcombinationoffinitelyma......
  • 优化配置Little Snitch for Mac的规则和设置
    LittleSnitchforMac是一款专业的macOS防火墙软件,它可以帮助你控制应用程序是否访问网络或者磁盘,并对系统不可信的进程和信息进行监控。如果你想保护你的Mac的网络安全,那么你需要了解如何配置和优化LittleSnitchforMac的规则和设置。本文将为你介绍一些基本的操作和技巧,让你能......
  • Chapter4 朴素贝叶斯
    朴素贝叶斯1.简介朴素贝叶斯是一种基于概率论的分类方法。它主要借助条件概率和贝叶斯公式来对样本进行分类。2.优缺点朴素贝叶斯优点:在数据较少的情况下仍然有效,可以处理多类别问题。缺点:对于输入数据的准备方式较为敏感。适用数据类型:标称型数据。3......
  • Chapter3 绘制决策树
    绘制决策树1.概述我们在上个博客已经学会使用代码来构造决策树了。但是,为了让构造出来的决策树具有可读性,我们还需要绘制决策树。2.设定样式#该代码的作用是设定节点和箭头的样式#该代码位于treePlotter.py文件中importmatplotlib.pyplotasplt'''在mat......
  • Chapter5 注解
    注解importmatplotlib.pyplotaspltimportnumpyasnpx=np.linspace(-3,3,50)y=2*x+1plt.figure(num=1,figsize=(8,5),)plt.plot(x,y,)ax=plt.gca()ax.spines['right'].set_color('none')ax.spines['top'].set_color('......
  • Chapter4 图例
    Chapter4图例图例的作用就是对所绘制的图像,进行解释。importmatplotlib.pyplotaspltimportnumpyasnpx=np.linspace(-3,3,50)y1=2*x+1y2=x**2plt.figure()#设置x轴的取值范围plt.xlim((-1,2))#设置y轴的取值范围plt.ylim((-2,3))#描述x轴plt......
  • Chapter3 设置坐标轴
    Chapter3设置坐标轴importmatplotlib.pyplotaspltimportnumpyasnpx=np.linspace(-3,3,50)y1=2*x+1y2=x**2plt.figure()plt.plot(x,y2)plt.plot(x,y1,color='red',linewidth=1.0,linestyle='--')#设置x轴的取值范围plt.xlim((-1,2))#设置y轴......
  • Chapter2 figure 基本用法
    figure基本用法importmatplotlib.pyplotaspltimportnumpyasnp#figure可以理解为表示图像的窗口#我们可以创建多个窗口#该代码的作用就是将每一个函数都分别显示在单独的figure中x=np.linspace(-3,3,50)y1=2*x+1y2=x**2'''figure参数有:第一个:num......