如何编写用于重构的elisp辅助函数

时间:2016-06-15 06:50:24

标签: emacs closures

我对emacs很陌生,我不确定我是否理解lisp实际应该采用的行为。

假设我有两个功能

(add-hook 'python-mode-hook (lambda () add-to-list (make-local-variable 'company-backends) 'company-jedi)) (add-hook 'js2-mode-hook (lambda () add-to-list (make-local-variable 'company-backends) 'company-tern))

我写了以下函数

(defun auto-complete (mode-hook backend) (add-hook mode-hook (lambda () add-to-list (make-local-variable 'company-backends) backend))) (auto-complete 'js2-mode-hook 'company-tern)

但它不起作用。我在线查看,发现这是因为elisp没有关闭! 那么,我该如何重构这两个代码块?

1 个答案:

答案 0 :(得分:2)

add-to-list是一个函数,因此您需要将它与括号一起使用,如(add-to-list...)。或者使用funcallapply调用它。

Elisp 关闭。执行以下一个

使用文件本地变量lexical-binding非 - nil

(defun auto-complete (mode-hook backend)
  (add-hook mode-hook
    (lambda ()
       (add-to-list (make-local-variable 'company-backends) backend))))

使用词法绑定,您将获得一个闭包,它封装了一个定义了变量backend的环境。它在该环境中的值是创建闭包时的值,但是当使用匿名函数时该变量仍然存在 - 您可以将其用作变量。

请参阅Elisp手册,节点"Body mixin"

无论lexical-binding的价值如何:

(defun auto-complete (mode-hook backend)
  (add-hook mode-hook
     `(lambda ()
       (add-to-list (make-local-variable 'company-backends) ',backend))))

在这种情况下, 没有关闭 ,并且 没有变量backend 在功能中。相反,该变量在其评估defun的上下文中被替换为其值。如果在调用匿名函数时不需要使用变量,则可以使用它,并且只需要它的值(在定义该函数时)。

如果使用闭包,那么匿名函数可以进行字节编译。如果你使用变量替换技术那么它就不能 - 在这种情况下,你不是在defun评估时(或用于字节编译)创建一个匿名函数。相反,您正在创建列表(lambda...),该列表稍后会被解释为函数。