Common Lisp学习之三:使用变量

Common Lisp支持词法变量和动态变量(Special variable)。在一定程度上,词法变量类似于类C语言中的局部变量,只在特定的作用域中有效,在作用域外部不可见;而动态变量类似于全局变量,访问其的代码可以在任意时刻对其进行重新绑定。

1 变量基础
Common Lisp是一种动态强类型的语言。变量可以指向任意类型的对象,而类型保存在对象信息里,而不是变量上;同时所有的类型错误都会被检测到。

let可以引入新变量。
(let (variables* ) body-form*)
当let表达式被求值时,所有变量赋值将首先被求值,并在body实行之前进行绑定。在let执行结束后,这些变量将重新引用在执行let前它们所引用的内容,如果有的话。 在下面的双顺序列表归并排序的代码中可以看到let的使用方法。
(define (merge list1 list2)
  (cond 
    ((empty? list1) list2)
    ((empty? list2) list1)
    (else
     (let ((f1 (car list1))
           (f2 (car list2)))
       (if (< f1 f2)
           (cons f1 (merge (cdr list1) list2))
           (cons f2 (merge list1 (cdr list2))))))))

let*也可以引入新变量,其与let的区别是:let创建的变量只能出现在body中,而let*创建变量可以出现在variables中引用。

函数形参也可以创建绑定。函数形参和Let变量的作用域被限定在引入此变量的形式内部,即函数定义和let形式内部,称之为绑定形式。如果嵌套的引入同名变量的绑定形式,那么内层变量绑定将覆盖外层绑定。类似于类C语言中的局部变量的嵌套。

2 词法变量与闭包
默认情况,CL中所有绑定形式都引入词法作用域变量。当词法作用域与嵌套函数一起使用时,就产生了闭包的概念。
(let ((count 0)) 
   (lambda () 
     (setf count (+ count 1))))

由于let将函数返回出去,当调用时并不在let的绑定形式内部。这时,CL会创建闭包对象,它封闭包装了其外部绑定形式内创建的绑定(此处为count=0)。闭包不仅能访问它所闭合的变量值,还可以保存每次变量变化的新值。闭包中的绑定将不受外部同名变量的影响。
单个闭包可以引用变量来闭合多个变量绑定,也可以多个闭合捕捉同一个绑定。

3 动态变量
CL提供了defvar和defparameter来创建全局变量,二者的区别是前者在变量已定义时,并不修改原有值。
当定义了全局变量后,可以在任意地方引用它。其好处在于不必到处传递它们。

有时我们希望在使用时,临时改变函数中某个变量的值,以实现不同的功能;而闭包的绑定不支持重新的绑定,因此引入动态变量来达到这个目的。例如:
(let ((*stdout* some-other)) (body)) 
在body中的代码引用stdout时都将引用let所建立的绑定,并且当body离开let时,stdout的绑定将随之消失。即在body中将动态查找stdout的绑定,如果当前命名空间内不存在此绑定,则递归向上一层查找。CL中动态变量必须使用special进行声明,而全局变量默认声明为special的。

4 常量 
常量是全局的,可以用defconstant进行定义,约定全局常量的结尾用+结束。

5 赋值
基本语法:(setf place value),当place是一个变量时,则将value绑定到place。
此外CL支持用户自定义数据结构,可以给结构的任意位置赋值。

支持一次设置多个:(setf x 1 y 2)
其返回最后一个被赋值的值。

6 按位置修改
(incr x n) n默认为1
(decr x n)
(rotatef x y) 交换x,y的值
(shiftf x y z) 返回第一个值,并将后续各值向前移动一位

你可能感兴趣的:(语法变量动态变量)