Lisp笔记(变量)
Common Lisp支持两种类型的变量:词法变量和动态变量。
一:
1)let(绑定)
在let形式体中,变量名将引用新创建的绑定。在let形式体执行结束后,这些变量名将重新引用在执行let之前他们所引用的内容。
(defun foo (x)
(format t “Parameter: ~a~% ” x)
(let ((x 2))
(format t “Outer LET: ~a~%” x)
(let ((x 3))
(format t “Inner LET: ~a~%” x))
(format t “Outer LET: ~a~%” x))
(format t “Parameter: ~a~%” x))
(foo 1)->
Parameter: 1
Outer LET:2
Inner LET: 3
Outer LET:2
Parameter:1
Nil
LET形式和函数形参中的变量是以完全相同的机制创建的。 LET只是一个展开到一个匿名函数调用的宏。
(let ((x 10)) (format t “~d” x)) == ((lambda (x) (format t “~d” x)) 10)
2)let* (绑定)
在let*中,每个变量的初始值形式都可以引用到那些变量列表早先引入的变量。
(let* ((x 10)
(y (+ x 10)))
(list x y))
(let ((x 10))
(let ((y (+ x 10)))
(list x y)))
结果:(10 20)
二:词法变量闭包
在函数定义被解释或者编译的时候,当时的自由变量的值,会跟函数的代码绑在一起,被放进一种叫做“闭包”的结构里.
在早期的lisp中
(defun f (y)
(let ((x 1))
(lambda (y) (* x y))))
这样调用(let ((x 2))
(funcall f 2)) 值为4.
而这样调用(funcall f 2),则会出错。
如果你在 emacs 里面显示 f 的值,它会打印出:'(lambda (y) (* x y))。这说明 f 的值其实是一个 S 表达式,而不是像 Scheme 一样的“闭包”(closure)。调用f的时候,比如(funcall f 2),y的值当然来自参数2,可是x的值是多少呢?到外层环境去找,看到哪个用哪个,看不到就报错!所以使用闭包。
三:动态变量(全局变量)
DEFVAR and DEFPARAMETER
DEFPARAMETER总是将初始值赋给命名的变量,而DEFVAR只有当变量未定义时才这样做。
(defvar *x* 10)
(defun foo () (“format t “X: ~d~%” *x*))
(defun bar ()
(foo)
(let ((*x* 20)) (foo))
(foo))
执行bar -> 10 -> 20 -> 10
(defun foo ()
(format t “Before: ~d~%” *x*)
(setf *x* (+ 1 *x*))
(format t “After: ~d~%” *x*))
(foo) -> Before:10
After:11
在运行bar
(bar)
Before:11
After:12
Before:20
After:21
Before:12
After:13
四:常量:(DEFCONSTANT)
(defconstant name initial-value-form [documentation-string])
五:赋值(SETF)
(defun foo (x) (setf x 10))
(let ((y 20)))
(foo y)
(print y))
打印出20
六:其他位置修改方式
(ROTATEF and SHIFTF)
(rotatef a b) == (let ((tmp a)) (setf a b b tmp) nil) 交换a and b.
(shiftf a b 10) == (let ((tmp a)) (setf a b b 10) tmp)
赋值
LISP JAVA/C/C++ Python
Simple variable: (setf x 10) x=10 x=10
Array: (setf (aref a 0) 10) a[0] = 10 a[0]=10
Hash table: (setf (gethash ‘key hash) 10) hash[‘key’]=10
Slot named ‘field’: (setf (field o) 10) o.field=10 o.field=10