Scheme r5rs letrec的用法

Scheme r5rs letrec的用法

说明,这是r5rs的用法. 

(letrec ((<variable> <init>) ...) <body>) 

假设((<variable> <init>) …)是变量定义块V,<body>是执行块B.

 

letrec最常见的用法就是用于绑定函数对象,让V里面定义的所有变量可以在运行时相互引用,不受位置前后的限制.比如:

> (letrec ((x (lambda () (+ y y)))
         (y 100))
    (+ (x) y))
300

这说明运行(+ (x) y)时,函数对象x可以读取y对象的值,尽管y在x之后才绑定的. 这一点letrec很像顶层的运作模式:

> (define x (lambda () (+ y y)))
> (define y 100)
> (+ (x) y)
300

只不过letrec创建的是一个本地作用域,而且语法上更简单.

 

将letrec替换为let*或let将出错:

> (let* ((x (lambda () (+ y y)))
         (y 100))
    (+ (x) y))
. . y: undefined;
 cannot reference an identifier before its definition
> (let ((x (lambda () (+ y y)))
         (y 100))
    (+ (x) y))
. . y: undefined;
 cannot reference an identifier before its definition
> 

 

let*最多只能让靠后的variable引用靠前的variable.交换一下x,y的定义位置,就正常了:

> (let* ((y 100)
         (x (lambda () (+ y y))))
    (+ (x) y))
300

而let限制更严格,各variable只能在body中被引用:

> (let ((y 100)
        (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 1)))))
           (iodd?
            (lambda (n)
              (if (zero? n)
                  #f
                  (ieven? (- n 1))))))
    (ieven? 3))  
#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 2)(b a)) b)
#<undefined>

对比顶层运作,不存在这种限制:

> (define a 2)
> (define b a)
> b
2

那为什么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 2)(b a)) b)
2

 

转载于:https://www.cnblogs.com/xiangnan/p/3387146.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/109986.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • python把数据存入txt_python数据保存为csv文件

    python把数据存入txt_python数据保存为csv文件参考:Python中文件的读取和写入PYTHON将list或/dict对象写入txt/json文件python(如何将数据写入本地txt文本文件)python中文件写入TXTPython中将变量按行写入txt文本中python把变量写入txt文件。Python读写文件python文件操作Python之文件读写Python程序输出到文件中python把一个unicode字符串…

  • 毫米波雷达跟激光雷达_毫米波雷达市场

    毫米波雷达跟激光雷达_毫米波雷达市场文章目录激光雷达超声波雷达摄像头毫米波雷达激光雷达激光雷达的波长介于750nm-950nm之间,以单线或多线束机制辐射光束,接收目标或环境的反射信号,以回波时间差和波束指向测量目标的距离和角度等空间位置参数。激光雷达主要优点如下:(1)波长短,测量精度高(2)多线束的探测,可以实现对场景的三维成像。激光雷达的主要缺点是:(1)抗干扰能力低,易受天气影响,在雨雪雾等天气的作用下,激光雷达使用受限。(2)激光发射、被测目标表面粗糙等因素都对测量精度有影响。(3)结构复杂,除激光

  • 解决keil注册机在win10无法打开问题[通俗易懂]

    解决keil注册机在win10无法打开问题[通俗易懂]解决keil注册机在win10无法打开问题刚开始笔者先以管理员模式打开,无效,弹出一个弹窗说为病毒文件以下提供一种解决办法,亲测有效就是安全模式里打开注册机详细做法如下:首先在设置——》恢复——》高级启动——》立即重新启动重启后,选择疑难解答——》高级选项——》启动设置——》重启——》选择4启动安全模式启动后在此模式就可以打开注册机,然后操作注册机后…

  • ADB 环境变量配置教学

    步骤如下:1、右击电脑图标点击电脑属性2、找到相关设置点击高级系统设置3、找到高级点击环境变量4、在系统变量中点击双Path5、点击新建6、确定

  • 软件开发的一些概念

    10.关系数据库(RelationalDatabases)关系数据库因为在大规模Web服务上缺乏可扩充性而颇受微词,然而,关系数据库仍然是近20年来计算机技术中最伟大的成就。关系数据库对处

    2021年12月23日
  • 鸿蒙树莓派4b,树莓派4B

    鸿蒙树莓派4b,树莓派4B作者:长空无名最近很多科技媒体都报道了树莓派4发布的消息。虽然整个板子做了大幅升级,基础价格却依然是35美元,称的上是业界良心。那号称史上性能最强的树莓派4,到底有哪些亮点呢?一起来看产品图。USB-C供电口1.5GHz四核64位ARMCortex-A72CPU1GB/2GB/4GBLPDDR4SDRAM内存(可选)全吞吐量千兆以太网(真千兆)双频802.11ac无线网络蓝牙5…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号