Jis*_*Yoo 5 lisp emacs elisp lexical-scope emacs24
2013 年 5 月更新:从 GNU Emacs 24.3.1 开始,(let .. (defun..)) 字节编译很好,没有警告,并且字节编译代码与未编译代码的工作方式相同。只是不要忘记将文件变量添加lexical-binding: t到要字节编译的文件中。现在不需要这个问题末尾的解决方法。
词法绑定 - Emacs Lisp 手册中有这样一段:
请注意,像 symbol-value、boundp 和 set 这样的函数仅检索或修改变量的动态绑定(即其符号值单元格的内容)。此外,defun 或 defmacro 主体中的代码不能引用周围的词法变量。
我不确定我是否理解了第二句话的意思。在以下应在词法绑定模式下运行的代码中, defun 主体中的代码成功引用了 name 的词法绑定值n。
(let ((n 0))
(defun my-counter ()
(incf n)))
(my-counter) ;; 1
(my-counter) ;; 2
Run Code Online (Sandbox Code Playgroud)
这句话只是说 (let .. (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 Code Online (Sandbox Code Playgroud)
这是测试上述代码的代码:
;; 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
Run Code Online (Sandbox Code Playgroud)
该代码至少在 Emacs 24.1.1 中不能很好地进行字节编译。我将以下代码保存在文件中foo.el,它使用setq来代替incf以避免cl库造成任何可能的影响:
;; -*- lexical-binding: t -*-
(let ((n 0))
(defun my-counter ()
(setq n (1+ n))))
Run Code Online (Sandbox Code Playgroud)
当我尝试对其进行字节编译(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'
Run Code Online (Sandbox Code Playgroud)
所有消息都表明构造主体中的代码defun无法引用周围的词法变量n无法像手册声明那样
实际上,当我加载字节编译代码(M-x load-filefoo.elc)并评估(my-counter)表单时,我得到了以下错误:
Debugger entered--Lisp error: (void-variable n)
...
Run Code Online (Sandbox Code Playgroud)
不幸的是,我不确定为什么代码在以源代码形式评估时似乎可以工作。