这是一个简短的elisp代码,它显示函数的行为取决于其变量的名称。这是一个错误吗?
使用变量x声明函数。当使用名为x之外的任何变量调用该函数时,它按预期工作。但如果使用名为x的变量调用它,则会失败!
我的系统是gub.tokyo.stp.isas.jaxa.jp上的2008-04-05的GNU Emacs 22.2.1(powerpc-apple-darwin8.11.0,Carbon Version 1.6.0)
将其粘贴到emacs缓冲区,将光标放在最后一个parehthesis之后,然后按下\ C-x \ C-e,以便在第二次调用时看到函数make-zero现在正常工作。
(progn
(defun make-zero (x)
"Simple function to make a variable zero."
(set x 0))
(setq x 10)
(insert "\n Variable x is now equal to " (number-to-string x))
(setq y 20)
(insert "\n Variable y is now equal to " (number-to-string y))
(insert "\n\n Let us apply make-zero to y")
(make-zero 'y)
(insert "\n Variable y is now equal to " (number-to-string y))
(insert "\n\n Let us apply make-zero to x")
(make-zero 'x)
(insert "\n Variable x is now equal to " (number-to-string x))
(insert "\n\n Why make-zero had no effect on x? Is it because the name of the
variable in the definition of make-zero, namely 'x', is the same as the name of
the variable when make-zero was called? If you change the name of the variable
in the definition of make-zero from x to z, this strange behaviour will
disappear. This seems to be a bug in elisp."))
答案 0 :(得分:2)
这不是一个错误,而是Elisp(以及一般的Lisp)动态绑定的本质。 '
没有传递引用(也就是说,它不像C / C ++中的&
),它传递了一个未经评估的符号;然后它评估的内容取决于它的评估范围,这意味着它获得了函数内范围的x
。
在Lisp-think中,通常的方法是使用宏。
(defmacro make-zero (x) (list 'set x 0))
或
(require 'cl)
(defmacro make-zero (x) `(set ,x 0))
答案 1 :(得分:2)
这不是一个错误。在阅读Scoping Rules For Variable Bindings的手册条目时,您是值得的。
您编写的函数调用set
,它接受一个符号(第一个参数的值)并将其值更改为第二个参数的值。您编写的make-zero
将x
本地绑定到其输入参数,因此当您传入符号x
时,设置更改它找到的x
的第一个绑定,这恰好发生在是当地的约束力。
这是一个不同的例子,让我们说你刚才有以下内容:
(defun print-something (something)
(set 'something "NEW VALUE")
(insert something))
(print-something "OLD") ; inserts "NEW VALUE"
查看代码片段,set
行更改something
的本地值是否有意义?
是否存在符号something
的全局设置并不重要。
另一个例子如下:
(defvar x "some global value") ;# could have used setq here
(let ((x "local binding"))
(set 'x "new value"))
您希望set
行改变哪种绑定?由let
创建的或defvar
创建的全局
您编写的函数(几乎)与let
完全相同,您可以为全局变量创建一个本地绑定。
如果你想传递对变量的引用,那么唯一安全的方法就是通过macros,我建议,但是直到你掌握了lisp的基础知识(b / c宏肯定更复杂)。也就是说,如果这是你的热情,不要让我阻止你潜入宏中。
可以找到编程Emacs lisp的一个很好的介绍here。
geekosaur's answer很好地展示了你如何实现自己想要的目标。