Emacs 我不知道';我不知道lisp宏如何构造它的扩展?什么';确切的步骤是什么?

Emacs 我不知道';我不知道lisp宏如何构造它的扩展?什么';确切的步骤是什么?,emacs,macros,lisp,expansion,Emacs,Macros,Lisp,Expansion,我试着写一个宏并按如下方式执行它。但它没有执行 (defmacro times_two (var) (* 2 var)) (times_two '(+ 1 2)) 在我的想象中,我认为扩展是(*2(+12))。执行之后,结果是6。但失败了 我不知道为什么。我读了Emacs lisp手册,但还是不懂。我想知道在构建扩展时,具体的步骤是什么。解释器做了什么?当我在Emacs中评估这些表单时,我在评估第二个表单时收到以下错误消息: 调试器已输入--Lisp错误:(错误的类型参数编号-or-marke

我试着写一个宏并按如下方式执行它。但它没有执行

(defmacro times_two (var) (* 2 var))
(times_two '(+ 1 2))
在我的想象中,我认为扩展是(*2(+12))。执行之后,结果是6。但失败了


我不知道为什么。我读了Emacs lisp手册,但还是不懂。我想知道在构建扩展时,具体的步骤是什么。解释器做了什么?

当我在Emacs中评估这些表单时,我在评估第二个表单时收到以下错误消息:

调试器已输入--Lisp错误:(错误的类型参数编号-or-marker-p(引号(+1-2)))
*(2(报价(+12)))
(lambda(var)(2 var)(引号(1 2))
(引用(1 2))
评估((乘以二(引号(+12)))
eval-last-sexp-1(无)
评估最后一个sexp(无)
交互式呼叫(评估上次sexp nil nil)
这是向您展示它是如何扩展宏的,它应该告诉您出了什么问题。(最终扩展位于顶部。)

带引号的表达式
”(+1 2)
被传递到times\u two宏,但带引号的列表不是
*
函数的有效参数

你真正想要的是:

(defmacro times_two(var)`(*2,var))
(乘以二(+12))

请记住,宏的结果通常是新的Lisp代码,而不是最终值。编写宏的目标是构造一个表单,该表单将为您提供所需的结果。因此,在大多数情况下,您的宏最终将使用quasikote(`)语法。

我怀疑您混淆了编译时和运行时。宏在编译时运行,生成要在运行时执行的代码。一般来说,很难保持这些直线,这使得编写宏很困难

在任何情况下,当我将此输入ielm时,我得到:

    ELISP> (defmacro times_two (var) 
       (* 2 var))
    times_two
    ELISP> (times_two '(+ 1 2))
    *** Eval error ***  Wrong type argument: number-or-marker-p, (quote (+ 1 2))
    ELISP> 
至少有一部分问题是'(+12),但当我删除引号时,以下情况也不会更好:

    ELISP> (times_two (+ 1 2))
    *** Eval error ***  Wrong type argument: number-or-marker-p, (+ 1 2)
    ELISP> 
似乎elisp正在我们放置“(+12)和(+12)的地方寻找一个数字或标记。让我们尝试使用一个数字:

    ELISP> (times_two 3)
    6
这很有效

有趣的是,该模型的宏观扩展给出:

    ELISP> (macroexpand '(times_two 3))
    6
这可能不是我们真正想要的

当我们编写宏时,我们希望返回要在运行时计算的表达式。因此,我们可以尝试以下方法,而不是返回数字:

    ELISP> (defmacro times_two (var) 
           `(* 2 ,var))
backtick(quasikote)是一种创建列表的方法,但也允许使用逗号进行插值。以这种方式定义时间_2给出:

    ELISP> (times_two (+ 1 2))
    6
以及扩大:

    ELISP> (macroexpand '(times_two (+ 1 2)))
    (* 2
       (+ 1 2))

这正是你想象的

失败时它说了什么?你在寻找
pp macroexpand last sexp
?@user1629065:如果你对其中一个答案感到满意,请将其标记为已接受的答案。