局部变量
在本节中将介绍局部变量,这将会使 定义函数变得更加容易
let 表达式
使用 let 表达式 可以 定义局部变量 。格式如下:
(let binds body)
- 变量 :在 binds定义的形式 中被 声明并初始化
- body :由 任意多个 S-表达式 构成
binds的格式如下:
[binds] → ((p1 v1) (p2 v2) ...) 声明了变量 p1 、 p2 ,并分别为它们赋初值 v1 、 v2 ......
声明局部变量 i 和 j,将它们与1、2绑定,然后求二者的和
(let ((i 1) (j 2)) (+ i j)) ; 3
let 表达式 可以 嵌套使用 :
例如:声明局部变量 i 和 j ,并将分别将它们与 1 和 i+2 绑定,然后求它们的乘积
(let ((i 1)) (let ((j (+ i 2))) (* i j))) ; 3
变量的 作用域(Scope)为body体 ,也就是说 变量只在body中有效 。下列代码会产生错误,因为 在变量 j 的作用域中没有变量 i 的定义 :
(let ((i 1) (j (+ i 2))) (* i j)) ; i: undefined
let* 表达式 可以用于 引用定义在同一个绑定中的变量 。实际上, let* 只是 嵌套的 let表达式 的语法糖 而已
(let* ((i 1) (j (+ i 2))) (* i j)) ; 3
函数 quadric-equation 用于计算二次方程 它需要三个代表系数的参数:a、b、c (ax^2 + bx + c = 0) 返回一个存放答案的实数表 通过逐步地使用let表达式,可以避免不必要的计算
;;;The scopes of variables d,e, and f are the regions with the same background colors. (define (quadric-equation a b c) (if (zero? a) 'error ; 1 (let ((d (- (* b b) (* 4 a c)))) ; 2 (if (negative? d) '() ; 3 (let ((e (/ b a -2))) ; 4 (if (zero? d) (list e) (let ((f (/ (sqrt d) a 2))) ; 5 (list (+ e f) (- e f))))))))) (quadric-equation 3 5 2) ; (-2/3 -1)
这个函数的行为如下:
- 如果二次项系数 a 为0,函数返回 'error
- 如果a ≠ 0,则将变量 d 与判别式 (b2 - 4ac) 的值绑定
- 如果 d 为 负数,则返回 '()
- 如果 d 不为 负数,则将变量 e 与 -b/2a 绑定
- 如果 d 为 0,则返回一个包含 e 的表
- 如果 d 是正数,则将变量 f 与 √(d/2a) 绑定,并返回由 (+ e f) 和 (- e f) 构成的表
词法闭包
实际上, let 表达式 只是 lambda 表达式的一个语法糖 :
(let ((p1 v1) (p2 v2) ...) exp1 exp2 ...) => ((lambda (p1 p2 ...) exp1 exp2 ...) v1 v2)
lambda表达式 用于 定义函数 ,它为 变量建立了一个作用域
在 Scheme 中,这个有效域由源代码的编写决定,这叫做 词法闭包 ( lexical closure )