使用& rest?一次增加几个变量?

时间:2013-01-24 08:46:52

标签: emacs elisp

我想创建一个允许的函数:

(incf vara varb varc vard)

而不是

(incf vara) (incf varb) (incf varc) (incf vard)

我不明白的是如何能够发送更多参数,如何在函数中定义它?

(defun inc(& rest arg)   (互动)   (mapcar'incf arg)   )

这增加了论证,但当然不会将它们保存回变量中。

如何解决这个问题?

2 个答案:

答案 0 :(得分:8)

如果您希望能够在不引用变量名称(my-incf a b c)ab的情况下将此表单编写为c,请将其设为宏而不是功能:

(defmacro incf+ (&rest vars)
  `(progn
     ,@(mapcar (lambda (var) `(incf ,var)) vars)))

使用macroexpand检查它是否扩展为正确的代码:

(macroexpand '(incf+ var1 var2 var3))
;; => (progn (incf var1) (incf var2) (incf var3))

因为默认情况下Emacs Lisp中的变量具有动态范围,所以可以使用带引号的变量名作为参数的函数完成几乎相同的操作。但宏版本的优点是,由于它在调用时扩展为代码,因此它也适用于词法绑定变量。 symbol-value仅适用于动态绑定变量。

您可以将以下内容放入文件并加载(在Emacs 24或更高版本中)来测试:

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

(defun incf+fun (&rest vars) 
  (mapc #'(lambda (var) (incf (symbol-value var))) vars))

(defun incf-macro-test ()
  (let ((a 5) (b 7) (c 11))
    (incf+ a b c)
    (list a b c)))

(defun incf-function-test ()
  (let ((a 5) (b 7) (c 11))
    (incf+fun 'a 'b 'c)
    (list a b c)))

评估(incf-macro-test)将返回(6 8 12),但(incf-function-test)将进入调试程序时出现(void-variable a)错误。

答案 1 :(得分:2)

应该有效:

(require 'cl)

(setq a 1)
(setq b 2)

(defun inc (&rest arg)
  (interactive)
  (mapc (lambda (x) (incf (symbol-value x))) arg))

(inc 'a 'b)

(message "%s %s" a b) => (2 3)

在执行(inc a b)之前,您必须引用每个参数,否则(inc 1 2)变为inc