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

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

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

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • idea激活码2021【2021.10最新】

    (idea激活码2021)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1STL5S9V8F-eyJsaWNlbnNlSWQi…

    2022年3月27日
  • kong网关架构_kong网关性能

    kong网关架构_kong网关性能Kong是一个使用了lua-nginx-module运行在Nginx之上的Lua应用。Kong是一个成熟的API网关解决方案。API网关,即APIGateway,是大型分布式系统中,为了保护内部服务而设计的一道屏障,可以提供高性能、高可用的API托管服务,从而帮助服务的开发者便捷地对外提供服务,而不用考虑安全控制、流量控制、审计日志等问题,统一在网关层将安全认证,流量控制,审计日志,黑白名单…

    2022年9月11日
  • aria2 bt tracker_ar接入路由器产品文档

    aria2 bt tracker_ar接入路由器产品文档vi/root/trackers-list-aria2.sh内容如下:#!/bin/bash#/usr/sbin/servicearia2stoplist=`wget-qO-https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt|awkNF|sed”:a;N;s/…

    2022年9月28日
  • Python中常用的第三方库_vscode如何使用第三方库

    Python中常用的第三方库_vscode如何使用第三方库第10章Python第三方库使用1.Python第三方库的获取和安装1.1pip工具安装1.2自定义安装1.3文件安装1.4pip工具使用2.pyinstaller库概述3.pyinstaller库与程序打包4.jieba库概述5.jieba库与中文分词6.wordcloud库概述7.wordcloud库与可视化词云1.Python第三方库的获取和安装Python第三方库依照安装方式灵活性和难易程度有3个方法,这3个方法是:pip工具安装、

    2022年10月14日
  • MS17010(永恒之蓝)漏洞利用与复现

    MS17010(永恒之蓝)漏洞利用与复现一:前言EhernalBlue通过Tcp端口445和139来利用SMBv1和NBT中的远程代码执行漏洞,恶意代码会扫描开放445文件共享端口的Windows机器,无需用户任何操作,只需要开机上网,攻击者就能在电脑和服务器中植入勒索软件。复现环境:攻击机kaliIP:10.10.10.136…

    2022年6月11日
  • ubuntu18.04安装opencv教程_Ubuntu18安装opencv

    ubuntu18.04安装opencv教程_Ubuntu18安装opencv最近opencv3.4.1发布了,想换个新的试试鲜,于是把配置的过程通过博文的方式记录下来,方便查阅。本教程原为3.3.0,但经过博主亲测,3.4.0、3.4.1皆适用1.去官网下载opencv,在本教程中选用的时opencv3.4.1,其他版本的配置方法异曲同工。下载链接http://opencv.org/releases.html,选择sources版本2.解压下…

    2022年9月1日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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