elisp同名参数问题


#1
(defun for-loop (op list-var)
  "对list-var中的元素,调用op"
  (if (not (eq list-var nil))
    (progn
      (funcall op (car list-var))
      (for-loop op (cdr list-var)))))

(defun append-to-list (list-var element-list)
  (let ((op (lambda (item) (add-to-list list-var item))))
    (for-loop op element-list)))

为了方便操纵列表,我在init.el中写了上面两个函数,调用时:

(setq list-1 '(1 2 3))
(append-to-list 'list-1 '(4 5 6))

但是emacs启动时,会报错,栈信息如下:

Debugger entered--Lisp error: (wrong-type-argument symbolp (4 5 6))
  add-to-list((4 5 6) 4)
  (lambda (item) (add-to-list list-var item))(4)
  funcall((lambda (item) (add-to-list list-var item)) 4)
  (progn (funcall op (car list-var)) (for-loop op (cdr list-var)))
  (if (not (eq list-var nil)) (progn (funcall op (car list-var)) (for-loop op (cdr list-var))))
  for-loop((lambda (item) (add-to-list list-var item)) (4 5 6))
  (let ((op (function (lambda (item) (add-to-list list-var item))))) (for-loop op element-list))
  append-to-list(list-1 (4 5 6))

只有当我把for-loop中的参数list-var换成别的,比如lst-var,就正常了,有没有人了解这是为什么?

看上去是for-loop和append-to-list中使用了同名参数list-var造成的,但是理论上不应该啊,两个函数没有什么关联,参数应该是局部环境的吧?


#2

#3

你的 lambda 先在 append-to-list 中定义,后在 for-loop 中执行,依据 Dynamic Binding 的使用变量的顺序,使用后者中的 list-var

现在一般都使用 Lexical Binding 了(即便你还未完全明白为什么,也是应该用 Lexical Binding)。而且我们不会在 Emacs Lisp 程序中使用 add-to-list,只会在自己配置中用。此外,你的 for-loop 已经有现成的 mapc 可用,至于 append-to-list 也可用现成的 append


#4

谢谢,确实是配置中的代码,我只是改了下,抽象了出必要的部分。