【问题标题】:elisp: defmacro with lambdaelisp:带有 lambda 的 defmacro
【发布时间】:2015-04-29 23:52:35
【问题描述】:

抱歉,我尝试了几次,但我无法构建简单的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 语句以使最后一个表单正常工作?谢谢!

【问题讨论】:

  • 为什么一定要宏?只需定义一个普通函数即可。
  • @barmar 是的,这似乎是更简单、更有用的解决方案。顺便说一句,我只是想在这里了解一下 defmacro。谢谢!

标签: emacs elisp


【解决方案1】:

你不需要宏。

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

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

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

【讨论】:

  • 虽然我同意,但我认为重要的是要指出您的代码只能在词法绑定模式下工作。 IE。你需要 -*- lexical-binding:t -*- 在包含此代码的文件的第一行。
【解决方案2】:

您的宏不适用于第二个示例的原因是 '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))))

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多