在命名函数中使用“let”的奇怪行为

时间:2014-03-10 20:32:09

标签: elisp

考虑以下MWE:

(setq a-cat 'derpy)

(let ((cats '(fluffy derpy)))
  (while cats
    (print cats)
    (setq cats (delq a-cat cats))
    (print cats)
    (print (pop cats))))

结果如下:

(fluffy derpy) ; original local binding of "cats".
(fluffy)       ; "cats" after the removal of 'derpy ("a-cat").
fluffy         ; the first and only element left in "cats" (with pop).
nil            ; empty "cats" after pop. the loop is over.

如果我多次评估表达式,结果总是相同的。但是如果我把它包装在一个函数定义中,就会发生奇怪的事情:

(setq a-cat 'derpy)

(defun cats-test ()
  (interactive)
  (let ((cats '(fluffy derpy)))
    (while cats
      (print cats)
      (setq cats (delq a-cat cats))
      (print cats)
      (print (pop cats)))))

(cats-test)

第一个结果(如预期的那样):

(fluffy derpy)
(fluffy)
fluffy
nil

第二个及后续结果:

(fluffy) ; "cats" local binding with only 1 element!??
(fluffy) ; "a-cat" wasn't found.
fluffy   ; (pop cats).
nil      ; end of loop.

如果我没有弄错的话,因为“猫”不是一个全局变量,所以在调用函数后它的值应保持不变。

如果我将表达式存储在匿名函数(使用(lambda ()))并调用它(使用funcall),结果与单独计算表达式相同,即没有奇怪的列表修改。 / p>

到底发生了什么?

编辑:

这可以防止在后续调用“cats-test”函数后修改列表:

(defun cats-test ()
  (interactive)
  (let ((cats (list 'fluffy 'derpy)))
    (while cats
      ...

现在每次调用该函数时,都会通过list函数(重新)定义“cats”局部变量的原始值。

0 个答案:

没有答案