为什么不评估Emacs lisp函数的参数?

时间:2014-07-17 06:16:18

标签: emacs elisp metaprogramming

我想用Emacs Lisp定义一个累加器列表并编写以下代码,但是我得到一个错误,说initV是一个void变量。似乎initV未在函数define-accum中进行评估。我哪里弄错了? (我只是想知道为什么,虽然我知道还有其他方法可以实现我的目标。)

(defun define-accum (name initV)
  (defalias name (lambda (v) (+ v initV))))

(setq accums '((myadd1 . 1)
               (myadd2 . 2)))

(dolist (a accums)
  (define-accum (car a) (cdr a)))

(message "result = %d" (+ (myadd1 1) (myadd2 1)))

3 个答案:

答案 0 :(得分:3)

您需要正确使用反引号。这对你有用,例如:

(defun define-accum (name initV)
  (defalias name `(lambda (v) (+ v ,initV))))

请参阅here了解

答案 1 :(得分:3)

除了使用反引号,您可以activate lexical binding(如果您使用的是Emacs 24或更新版本)。例如,如果我将您的代码放在.el文件中并将其放在第一行:

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

然后我得到输出:

result = 5

这是有效的,因为define-accum中的lambda函数将在定义它的环境中引用initV(从而在参数列表中选择变量),并在此变量上创建闭包。使用动态绑定(默认),该函数将在调用它的环境中查找initV

答案 2 :(得分:1)

添加一些其他人所说的内容 -

  1. 如果变量(initV)从未实际使用作为变量,那么实际上它在累加器时的定义是所有需要的,然后不需要封装该变量及其值的词法闭包。在这种情况下,@ juanleon描述的方法就足够了:它只使用定义时的值 - 当调用函数时,变量不存在(如你所发现的那样)。

  2. 另一方面,词法闭包方法允许函数进行字节编译。在反引号方法中,函数仅在运行时由表示lambda表单的 list 表示。如果lambda表单代表昂贵的代码,那么使用词法闭包方法是有意义的,即使(在这种情况下)变量不是真正需要的(作为变量)。

  3. 但是你总是可以明确地对该函数进行字节编译(例如define-accum中的## NAME ##。这将解决上面#2中提到的低效率。

    < / LI>