Scheme r5rs letrec的用法
说明,这是r5rs的用法.
(letrec ((<variable> <init>) ...) <body>)
假设((<variable> <init>) ...)是变量定义块V,<body>是执行块B.
letrec最常见的用法就是用于绑定函数对象,让V里面定义的所有变量可以在运行时相互引用,不受位置前后的限制.比如:
> (letrec ((x (lambda () (+ y y)))
(y ))
(+ (x) y))
这说明运行(+ (x) y)时,函数对象x可以读取y对象的值,尽管y在x之后才绑定的. 这一点letrec很像顶层的运作模式:
> (define x (lambda () (+ y y)))
> (define y )
> (+ (x) y)
只不过letrec创建的是一个本地作用域,而且语法上更简单.
将letrec替换为let*或let将出错:
> (let* ((x (lambda () (+ y y)))
(y ))
(+ (x) y))
. . y: undefined;
cannot reference an identifier before its definition
> (let ((x (lambda () (+ y y)))
(y ))
(+ (x) y))
. . y: undefined;
cannot reference an identifier before its definition
>
let*最多只能让靠后的variable引用靠前的variable.交换一下x,y的定义位置,就正常了:
> (let* ((y )
(x (lambda () (+ y y))))
(+ (x) y))
而let限制更严格,各variable只能在body中被引用:
> (let ((y )
(x (lambda () (+ y y))))
(+ (x) y))
. . y: undefined;
cannot reference an identifier before its definition
当你表达式里含有一些相互递归的函数时,letrec非常合适.例如下面这个判断奇偶数的函数:
> (letrec ((ieven?
(lambda (n)
(if (zero? n)
#t
(iodd? (- n )))))
(iodd?
(lambda (n)
(if (zero? n)
#f
(ieven? (- n ))))))
(ieven? ))
#f
看起来letrec很强大的样子,那么,letrec的限制是什么呢?(准确说是r5rs的限制.Racket不存在这种限制)
letrec要求<init>必须能够独立成值,否则letrec绑定就会出问题.以下摘自r5rs:
One restriction on letrec is very important: it must be possible to evaluate each <init> without assigning or referring to the value of any <variable>.In the most common uses of letrec, all the <init>s are lambda expressions and the restriction is satisfied automatically.
比如下面这个,b绑定不了2:
> (letrec ((a )(b a)) b)
#<undefined>
对比顶层运作,不存在这种限制:
> (define a )
> (define b a)
> b
那为什么lambda表达式能够自动地满足这个要求呢?
因为一个lambda表达式是一个函数对象,它本身就是一个值.相当于100这种整数对象.
Scheme不会在定义时严格检查lambda.比如里面的某变量是否已绑定对象,lambda被执行时才知道会不会出问题.
> (lambda (n)(xxx? (- n 1)))
#<procedure>
> ((lambda (n)(xxx? (- n 1))) 3)
. . xxx?: undefined;
cannot reference undefined identifier
>
那let*存在的意义是什么? 看这种情况:
> (letrec ((a 2)(b a)) b)
#<undefined>
> (let* ((a 2)(b a)) b)
2
>
let*能让(b a)读取前面的定义(a 2),从而让b等于2.letrec就不行.
而let对比let*限制更多,因此性能应该是更好的.在let和let*都能正常运行的时候,显然应该选择let.
这应该就是let,let*和letrec各自存在的意义吧.
注:方言Racket的letrec没有此限制.
> (letrec ((a )(b a)) b)
Scheme r5rs letrec的用法的更多相关文章
- call/cc 总结 | Scheme
call/cc 总结 | Scheme 来源 https://www.sczyh30.com/posts/Functional-Programming/call-with-current-contin ...
- 算法语言Scheme修订6报告 R6RS简体中文翻译
算法语言Scheme修订6报告 R6RS简体中文翻译 来源 https://r6rs.mrliu.org/ MICHAEL SPERBERR. KENT DYBVIG, MATTHEW FLATT ...
- let区别(关于racket和r5rs)
R5RS is the Revised5 Report on the Algorithmic Language Scheme.参考http://www.schemers.org/Documents/S ...
- scheme 教程 #lang racket
scheme 教程 #lang racket 来源 https://blog.csdn.net/yemeishenme/article/details/51471037 原文: https://le ...
- 开始学习Scheme
开始学习Scheme 函数式编程(Functional Programming)是在MIT研究人工智能(Artificial Intelligence)时发明的,其编程语言为Lisp.确切地说,L ...
- Android基础学习第三篇—Intent的用法
写在前面的话: 1. 最近在自学Android,也是边看书边写一些Demo,由于知识点越来越多,脑子越来越记不清楚,所以打算写成读书笔记,供以后查看,也算是把自己学到所理解的东西写出来,献丑,如有不对 ...
- awk 的一些用法
awk,我觉得是Linux里面处理文本最精妙的命令,它是一个行处理的命令,它最初级的用法是:给定一些简单的pattern,然后按照这个pattern 去搜索匹配的行.它的高级用法是用awk来编程,除了 ...
- Android网页中tel,sms,mailTo,Intent,Market协议用法总结
tel:协议---拨打电话 <a href="tel:">调出拨号界面</a> <a href="tel:10086">调 ...
- 【Win10 UWP】URI Scheme(一):Windows Store协议的解析和使用
协议是Windows Phone和Windows Store应用的一个重要特点,可以做到在不同应用之间进行互相呼起调用.小小协议,学问大着呢.我打算写几篇关于协议在UWP中使用的文章. 这一讲的主要对 ...
随机推荐
- Frame
Frame意为框架,是在屏幕上的一个矩形区域. Frame主要作为其他组件的框架基础,或为其他组件提供间距补充. 何时使用Frame组件呢? Frame组件主要用于在复杂的布局中奖其他组件分组,也用于 ...
- [python]_ELVE_pip2和pip3如何共存
作者:匿名用户链接:https://www.zhihu.com/question/21653286/answer/95532074来源:知乎著作权归作者所有,转载请联系作者获得授权. 想学习Pytho ...
- Java 嵌套类基础详解
目录 1. 什么是嵌套类? 2. 为什么要使用嵌套类? 3. 嵌套类的类型 4. 静态嵌套类 5. 非静态嵌套类 5.1 成员内部类 5.2 局部内部类 5.3 匿名内部类 6. 嵌套接口 1. 什么 ...
- JS实现手机访问pc网址自动跳转到wap网站
之前写pc端直接跳转wap端一直是后端java写的,跟js一样都是根据navigator.userAgent来判断设备是电脑还是手机的,我知道这种前端也可已完成的功能,只是后台比较强势,本人本着以和为 ...
- 关于自定义view--实现自定义水波纹效果
开发中的东西太多,怕自己忘记了,简单记录一下. 声明:此控件借鉴了大佬的想法,在此感谢大佬提供的支持,我只是把大佬的想法拿出来而已. ok,废话到此结束,看效果: 分析一下,我们可以看到,图中有两个圆 ...
- 阅读DSSS.py 并修改成支持python3.6
项目地址:https://github.com/stamparm/DSSS 功能:一款小型注入工具 代码如下URL:https://github.com/stamparm/DSSS/blob/mast ...
- BZOJ4079 [Wf2014]Pachinko
完整题面: 设f(i,j)表示路径经过(i,j)这个点的概率,列出方程消元. 但暴力消元的复杂度是$O((nm)^3)$,注意每一次消元只会影响前后m个方程,所以我们可以对于第i行,只存[i-m,i+ ...
- Android Studio创建/打开项目时一直处于Building“project name”Gradle project info的解决办法
重新安装了Android studio 之后, 启动android studio,打开原来的项目,界面一直停留在: 一直停留在此界面的原因是:Android studio 在下载 Gradle ,但是 ...
- Python 线程池,进程池,协程,和其他
本节内容 线程池 进程池 协程 try异常处理 IO多路复用 线程的继承调用 1.线程池 线程池帮助你来管理线程,不再需要每个任务都创建一个线程进行处理任务. 任务需要执行时,会从线程池申请线程,有则 ...
- .Net及C#基础知识,面试宝典
作为你一.Net和C#开发这些知识,你是否掌握了,你是否算的上一名入门的程序员? 技术不行并不可怕,可怕的是你不知道自己还需做哪一方面的提升,本篇文字本人的一些面试时所经常涉及的问题,并且在网上收集了 ...