Dio*_*nco 5 lisp variables lambda scope common-lisp
如果我们为变量赋值:
(setf i 10)
Run Code Online (Sandbox Code Playgroud)
然后创建一个关闭它的lambda函数:
(setf f #'(lambda () i))
Run Code Online (Sandbox Code Playgroud)
我们有这种行为
(incf i) ;=> 11
(funcall f) ;=> 11
Run Code Online (Sandbox Code Playgroud)
相反,我希望函数始终返回i
创建函数时的值.例如:
(incf i) ;=> 11
(funcall f) ;=> 10
Run Code Online (Sandbox Code Playgroud)
基本上我想i
变成lambda体内的文字.这可以在Common Lisp中完成吗?原因是我在一个循环中创建了多个lambda,并且需要在它们的主体中使用索引,而在创建之后它们不会变化.
只需将变量与值的副本绑定即可.例如:
(let ((i i))
(lambda () i))
Run Code Online (Sandbox Code Playgroud)
这实际上是迭代结构的一个重要技术,因为类似于
(loop for i from 1 to 10
collecting (lambda () i))
Run Code Online (Sandbox Code Playgroud)
可能会在相同的变量上返回十个闭包,因此有必要写:
(loop for i from 1 to 10
collecting (let ((i i)) (lambda () i)))
Run Code Online (Sandbox Code Playgroud)
如果你真的只需要一个返回值的函数,你也可以不断使用(但我希望真正的用例更复杂):
(loop for i from 1 to 10
collecting (constantly i))
Run Code Online (Sandbox Code Playgroud)
在某些情况下,迭代表单中的歧义实际上是由标准指定的.例如,对于dotimes,dolist
它是依赖于实现的,是否dotimes在每次迭代时建立var的新绑定,或者它是否在开始时为var建立一次绑定,然后在任何后续迭代上分配它.
更原始的做,但是,实际上规定了有一组绑定的形式,并且使它们在每次迭代(强调)更新日期:
在除第一次之外的每次迭代开始时,变量如下更新....
这种模糊性使实现更具灵活性. 例如,Dolist可以使用以下任一方式定义:
(defmacro dolist ((var list &optional result) &body body)
`(progn (mapcar #'(lambda (,var)
,@(ex:body-declarations body)
(tagbody
,@(ex:body-tags-and-statements body)))
,list)
(let ((,var nil))
,result)))
Run Code Online (Sandbox Code Playgroud)
(defmacro dolist ((var list &optional result) &body body)
(let ((l (gensym (string '#:list-))))
`(do* ((,l ,list (rest ,l))
(,var (first ,l) (first ,l)))
((endp ,l) ,result)
,@body)))
Run Code Online (Sandbox Code Playgroud)