elisp:使用 lambda 的 defmacro

elisp: defmacro with lambda

抱歉,我尝试了几次,但我无法构建简单的 defmacro - 谁能帮我解决这个问题:

所以,我想定义将扩展为的宏:

(define-key keymap "*" (lambda ()
                          (interactive)
                          (some-func "*")))

我试过类似的方法:

(defmacro wrap-and-define-key (keymap key func)
  `(define-key ,keymap ,key (lambda () (interactive) (,func ,key))))

它适用于:

(wrap-and-define-key keymap key func)

但不适用于

(wrap-and-define-key keymap key 'func)

如何更改 defmacro 语句使最后一个表单有效?谢谢!

好的,找到一些可行但不确定的东西 - 这是一个优雅的解决方案:

(defmacro wrap-and-define-key (keymap key func)
  `(define-key ,keymap ,key '(lambda () (interactive) (eval (list ,func ,key)))))

你不需要宏。

(defun wrap-and-define-key (keymap key func)
  (define-key keymap key (lambda () (interactive) (funcall func key))))

(不要引用 lambda 形式。避免 eval。)

不确定你为什么想要这个,但无论如何,这应该能满足你的要求。

您的宏在第二个示例中不起作用的原因是 'func 作为带引号的参数传递,因为宏的参数不会自动求值。所以宏中的 lambda 扩展为:

(lambda () (interactive) ('func key))

但是这样调用时不能引用函数名。只有 lambda 或不带引号的符号才能作为函数调用表达式中的第一项出现。如果将宏更改为:

(defmacro wrap-and-define-key (keymap key func)
  `(define-key ,keymap ,key (lambda () (interactive) (funcall ,func ,key))))

它会起作用的。当调用 lambda 时,'func 被计算为普通 func 符号并传递给 funcall。 funcall 然后在函数命名空间(Elisp 是 Lisp-2)中查找符号并调用它。

正如另一个答案中所建议的,您可以使用函数来完成此操作。无论是否启用词法模式,此功能都将起作用:

(defun wrap-and-define-key (keymap key func)
  (define-key keymap key `(lambda () (interactive) (funcall ',func ,key))))