Emacs:defun或defmacro体内的代码不能引用周围的词法变量?

2013年5月更新:从GNU Emacs 24.3.1开始,(let ..(defun ..))bytecompiles就绪没有警告,字节编译代码与未编译代码的工作方式相同.只是不要忘记将文件变量lexical-binding:t添加到要进行字节编译的文件中.现在没有必要在这个问题的最后找到解决方法.

Lexical Binding – Emacs Lisp Manual有这一段:

Note that functions like symbol-value, boundp, and set only retrieve or modify a variable’s dynamic binding (i.e. the contents of its symbol’s value cell). Also, the code in the body of a defun or defmacro cannot refer to surrounding lexical variables.

我不确定我是否正确地理解了第二句话的含义.在以下应该在词法绑定模式下运行的代码中,defun正文中的代码成功引用了名称n的词法绑定值.

(let ((n 0))
  (defun my-counter ()
    (incf n)))

(my-counter) ;; 1
(my-counter) ;; 2

这句话只是说(让…(defun ..))是一种不好的做法吗?

解决方法:

;; -*- lexical-binding: t -*-

;; a way to define the counter function without byte-compile error or warning

(defvar my--counter-func
  (let ((n 0))
    (lambda ()
      (setq n (1+ n)))))

(defun my-counter ()
  (funcall my--counter-func))

;; another way to define the counter function, again without byte-compile error or warning

(fset 'my-another-counter
      (let ((n 0))
        (lambda ()
          (setq n (1+ n)))))

以下是测试上述代码的代码:

;; run:
;; emacs -q --load path-to-the-el-file-of-this-code.el

(load "path-to-file-defining-my-counter.elc") ;; loading the ELC file to test if byte-compiled code runs as expected.

(print (my-counter)) ;; 1
(print (my-counter)) ;; 2

(print (my-another-counter)) ;; 1
(print (my-another-counter)) ;; 2

最佳答案 至少在Emacs 24.1.1中,代码不能很好地进行字节编译.我将以下代码保存在foo.el文件中,该文件使用setq代替incf,以避免cl库产生任何可能的影响:

;; -*- lexical-binding: t -*-

(let ((n 0))
  (defun my-counter ()
    (setq n (1+ n))))

当我尝试对其进行字节编译时(M-x byte-compile-filefoo.el),我收到以下警告消息:

foo.el:3:1:Warning: Function my-counter will ignore its context (n)
foo.el:3:1:Warning: Unused lexical variable `n'
foo.el:5:11:Warning: reference to free variable `n'
foo.el:5:17:Warning: assignment to free variable `n'

所有消息都指示defun构造体中的代码不能像手动声明的那样引用周围的词汇变量n.

实际上,当我加载字节编译的代码(M-x load-filefoo.elc)并评估(my-counter)表单时,我得到了以下erorr:

Debugger entered--Lisp error: (void-variable n)
  ...

不幸的是,我不确定为什么代码在以源代码的形式进行评估时似乎有效.

点赞