TSPL学习笔记(2):过程和变量绑定
变量的引用
语法: variable
返回: variable的值
如果在某个范围内存在对某个标识符的变量绑定,那么当这个标识符以表达式的形式出现的时候被认为是其所绑定变量的值.
在引用一个标识符的时候,如果这个标识符没有被绑定为变量,关键字,记录名或其它的实体那么解释器/编译器将会报语法错误.定义(通过define表达式)的有效范围是整个域(例如lambda表达式的整个body),所以只要引用定义的地方没有对定义求值则相关的定义不必出现在它被引用之前.例如:
(define f
(lambda (x)
(g x)))
(define g
(lambda (x)
(+ x x)))
g
的定义出现在对它的引用(g x)
之后,但定义f
的时候并不对(g x)
求值所以上述代码是合法的.
而下面的代码则是非法的:
(define q (g 3))
(define g
(lambda (x)
(+ x x)))
因为在q
的定义中需要对g
求值,而在这个位置上q
的定义还没完成.
Lambda
语法:(lambda formals body1 body2 ...)
返回:一个过程
库:(rnrs base),(rnrs)
lambda语法形式用于创建过程.任何创建过程或建立局部变量绑定的语法形式最终都是通过一系列的lambda或case-lambda语句实现的.
在lambda语句中,出现在formals
中的变量都是过程参数,body1,body2 ...
组成了过程的body.
形参实参绑定:
- 如果
formals
是一个完整的由变量组成的list
,例如:(x y x),则每个变量分别与其对应的实参绑定,实参的数量太多或太少都会引发异常 - 如果
formals
是一个单一的变量,例如:z,则所有实参形成一个list与z绑定. - 如果
formals
不是一个完整的list
,例如:(x y . z),则相应的实参绑定到x,y,其余实参形成一个list与z绑定.如果实参数量太少会引发异常.
当body被求值的时候,body中的表达式会按顺序被求值,而最后一个表达式的求出的值作为过程的返回值被返回.
Case-Lambda
Scheme的lambda不能直接支持不同参数数量的过程定义重载,要实现这个重载定义需要使用case-Lambda
.
语法: (case-lambda clause ...)
返回: 一个过程
库: (rnrs control) , (rnrs)
一个case-lambda表达式由一系列的子句组成,每一条子句都与lambda表达式类似:
[formals body1 body2 ...]
由case-lambda表达式创建的过程被调用的时候,按字句定义的顺序将其formals
与实参匹配,匹配规则与lambda创建的过程一样,第一个被匹配成功的子句会被求值,如果没有一个子句匹配成功会引发异常.
例如下面是一个case-lambda的例子:
(define make-list
(case-lambda
[(n) (make-list n #f)]
[(n x)
(do ([n n (- n 1)] [ls '() (cons x ls)])
((zero? n) ls))]))
局部绑定
语法: (let ((var expr) ...) body1 body2 ...)
返回: 最后一个body表达式的值
库: (rnrs base) , (rnrs)
let表达式建立局部变量绑定,var被绑定为expr求的值,在let表达式的body内可以引用var.let表达式的body由一系列的body 1 body 2 ...
子句组成,其求值计算与lambda一样.
let
与let*
,letrec
,letrec*
的主要区别在于,var在expr的作用域内是不可见的,所以在expr中引用var是非法的.
let
,letrec
和let*
,letrec*
的区别在于,如果有多个(var expr)
,前两者对expr
的求值顺序是不确定的,而后两者严格按照从左到右的顺序对expr
求值.
let
是一种扩展语法其语法定义如下:
(define-syntax let
(syntax-rules ()
[(_ ((x e) ...) b1 b2 ...)
((lambda (x ...) b1 b2 ...) e ...)]))
语法: (let* ((var expr) ...) body1 body2 ...)
返回: 最后一个body表达式的值
库: (rnrs base) , (rnrs)
如上所述,与let唯一的区别在于expr
的求值顺序.
任何的let*
表达式都可以转化为用嵌套的let
表达式实现:
(define-syntax let*
(syntax-rules ()
[(_ () e1 e2 ...)
(let () e1 e2 ...)]
[(_ ((x1 v1) (x2 v2) ...) e1 e2 ...)
(let ((x1 v1))
(let* ((x2 v2) ...) e1 e2 ...))]))
语法: (letrec ((var expr) ...) body 1 body 2 ...)
返回: 最后一个body表达式的值
库: (rnrs base) , (rnrs)
letrec
与let
和let*
的唯一区别在于var在expr中是可见的,所以可以在expr中递归的引用var,例如:
(letrec ([sum (lambda (x)
(if (zero? x)
0
(+ x (sum (- x 1)))))])
(sum 5)) -> 15
语法: (letrec* ((var expr) ...) body1 body2 ...)
返回: 最后一个body表达式的值
库: (rnrs base) , (rnrs)
与letrec
类似只是expr
的求值顺序严格按照从左往右执行.
多值局部绑定
语法: (let-values ((formals expr) ...) body1 body2 ...)
语法: (let*-values ((formals expr) ...) body1 body2 ...)
返回: 最后一个body表达式的值
库: (rnrs base) , (rnrs)
let-values
和let*-values
可以方便的为formals
中的变量绑定值,例如:
(let-values ([(a b) (values 1 2)] [c (values 1 2 3)])
(list a b c)) -> (1 2 (1 2 3))
a被与1绑定,b与2绑定,c与(1 2 3)绑定.
上述代码还可以改成如下等价形式:
(let-values ([(a b c) (values 1 2 (list 1 2 3))])
(list a b c))
变量定义
语法: (define var expr)
语法: (define var)
语法: (define (var0 var1 ...) body1 body2 ...)
语法: (define (var0 . varr ) body1 body2 ...)
语法: (define (var0 var1 var2 ... . varr ) body1 body2 ...)
库: (rnrs base) , (rnrs)
第一种语法形式将var与expr绑定,第二种等价于(define var unspecified)
其余的分别等价于:
(define var0
(lambda (var1 ...)
body1 body2 ...))
(define var0
(lambda varr
body1 body2 ...))
(define var0
(lambda (var1 var2 ... . varr)
body1 body2 ...))
赋值
语法: (set! var expr)
返回: 未定义
库: (rnrs base) , (rnrs)
TSPL学习笔记(2):过程和变量绑定的更多相关文章
- C++11 学习笔记 std::function和bind绑定器
C++11 学习笔记 std::function和bind绑定器 一.std::function C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法 ...
- JVM学习笔记——类加载过程
JVM学习笔记——类加载过程 类加载模型——双亲委派模型(Parents Delegation Model)也可称为“溯源委派加载模型” Java的类加载器是一个运行时核心基础设施模块,主要是启动之初 ...
- JavaScript学习笔记——JS中的变量复制、参数传递和作用域链
今天在看书的过程中,又发现了自己目前对Javascript存在的一个知识模糊点:JS的作用域链,所以就通过查资料看书对作用域链相关的内容进行了学习.今天学习笔记主要有这样几个关键字:变量.参数传递.执 ...
- JavaScript学习笔记(八)——变量的作用域与解构赋值
在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...
- C#.NET学习笔记7--11---算术运算符,变量赋值,变量的交换,布尔表达式1,布尔表达式2
C#.NET学习笔记7---算术运算符 2013/9/6 技术qq交流群:JavaDream:251572072 教程下载,在线交流:创梦IT社区:www.credream.com 1.Consol ...
- vue学习笔记(三)class和style绑定
前言 通过上一章的学习vue学习笔记(二)vue的生命周期和钩子函数,我们已经更近一步的知道了关于vue的一些知识,本篇博客将进一步探讨vue其它方面的内容,vue中关于class和style绑定,关 ...
- vue学习笔记(六)表单输入绑定
前言 在上一章vue学习笔记(四)事件处理器这一篇博客的内容中,我们已经了解vue是如何绑定事件的,而本篇博客主要讲解的是vue中表单输入的绑定,通常我们自己提交信息的时候都是通过表单将信息到服务器的 ...
- 【Python灰帽子--黑客与逆向工程师的Python编程之道】我的学习笔记,过程.(持续更新HOT)
我的学习笔记---python灰帽子 世界让我遍体鳞伤,但伤口长出的却是翅膀. -------------------------------------------- 前言 本书是由知名安全机构Im ...
- go 学习笔记之有意思的变量和不安分的常量
首先希望学习 Go 语言的爱好者至少拥有其他语言的编程经验,如果是完全零基础的小白用户,本教程可能并不适合阅读或尝试阅读看看,系列笔记的目标是站在其他语言的角度学习新的语言,理解 Go 语言,进而写出 ...
随机推荐
- 细说ASP.NET Windows身份认证
上篇博客我谈到了一些关于ASP.NET Forms身份认证方面的话题,这次的博客将主要介绍ASP.NET Windows身份认证. Forms身份认证虽然使用广泛,不过,如果是在 Windows Ac ...
- [转载]安装Oracle11gR2先决条件检查失败的详细解决处理过程
原文地址:安装Oracle11gR2先决条件检查失败的详细解决处理过程作者:四海名汀 最近在32位Win7系统下安装Oracle11g发现一系列错误,现将详细的错误解决过程记录如下,以供大家参考. 一 ...
- 微信小程序页面返回传参的问题
比如提交问题,然后需要返回之前页面,由于onLoad只会加载一次,所以不会触发,但是我们页面又需要刷新,那怎么办? 1.onLoad与onShow区别 onLoad:监听页面加载.一个页面只会调用一次 ...
- Mongodb对集合(表)和数据的CRUD操作
一.集合(对应数据库的表) 1.查看当前库里的所有集合 show collections 2.新建集合 显式创建 db.createCollection("user") 隐式创建 ...
- VBScript.RegExp 正则表达式excel vba 学习经验
1) 手动引用(前期绑定) 点击VBE编辑器菜单:工具 - 引用,选取: Microsoft VBScript Regular Expressions 5.5 Dim regex As New ...
- Python 隔离沙箱 virtualenv
我认为Python一个很大的优势就是官方网站给出的众多的软件包,几乎能帮助你实现你想要的任何功能,避免了重复开发的劳动,但是零零碎碎的包,以及每个包的各种各样的版本管理就成为了一个比较棘手的问题,因此 ...
- 转发-基于ASP.NET MVC 4/5 Razor的模块化/插件式架构实现
基于ASP.NET MVC 4/5 Razor的模块化/插件式架构实现 概述 在日常开发中, 我们经常谈起模块化/插件化架构,这样可既可以提高开效率,又可以实现良好的扩展性,尤其对于产品化的系统有 ...
- 第三部分:Android 应用程序接口指南---第二节:UI---第四章 Action Bar
第4章 Action Bar Action Bar是一个能用于确定应用程序和用户的位置,并提供给用户操作和导航模式的窗口功能.如果需要显著地展示当前用户的操作或导航,应该使用Action Bar,因为 ...
- Android studio的主题颜色修改
1.选择喜欢的主题 http://color-themes.com/?view=index 好几十款,总有一款你喜欢 2.下载你喜欢的主题,注意是jar文件 .File -> Import Se ...
- 省市区三级联动——思路、demo、示例
说明(2017-12-13 11:03:58): 1. 这个功能应该是注册的时候非常.常用的了,不过现在都是微信登录,手机端自动获取位置什么的,可能就网站还用用吧! 2. 这个东西的难点在于统计各地省 ...