【问题标题】:Macros and how to trace them宏以及如何跟踪它们
【发布时间】:2017-12-05 22:30:36
【问题描述】:

trace 宏对于调试非常有用。但是,当用于任何宏时,它会停止。就像我尝试执行以下操作一样:

CL-USER> (trace push)

然后,它会报错:

can't use encapsulation to trace anonymous function #<FUNCTION (MACRO-FUNCTION
                                                                PUSH) {100053FB9B}>
   [Condition of type SIMPLE-ERROR]

嗯,这很明显,因为trace 的 clhs 页面清楚地定义了函数。那么,Common Lisp 中没有任何跟踪宏的工具的原因是什么?
在 Common Lisp 中是否有任何其他(非常规)方法来跟踪宏?

【问题讨论】:

  • 好吧,如果宏在编译时扩展,你将如何跟踪它们的调用?您也许可以编写一个宏来选择扩展宏的第一种形式并在其上调用trace
  • 在什么情况下要跟踪宏?在 SBCL 中,似乎可以使用非标准的 :ENCAPSULATE 参数来跟踪:(trace push :encapsulate nil)。通常宏扩展是调试宏的更好方法(使用 Sly,您也可以使用宏步)。宏中的任何复杂逻辑都可以在单独的函数中实现,也可以正常跟踪。
  • 谢谢@jkiiski!当我需要知道它在程序中实际做了什么时,宏扩展内置宏(如push)并没有多大帮助。

标签: debugging macros common-lisp trace


【解决方案1】:

Common Lisp 标准仅提及函数的跟踪。在编译的实现中,宏扩展通常发生在编译时,因此通常不支持宏的跟踪。

但一些 Common Lisp 实现可以通过 Lisp 解释器 (!) 跟踪宏:

CLISP 可以跟踪宏

[1]> (defmacro foo (a) a)
FOO
[2]> (trace foo)
;; Tracing macro FOO.
(FOO)
[3]> (loop for i below 4 collect (foo i))
1. Trace: (FOO I)
1. Trace: FOO ==> I
1. Trace: (FOO I)
1. Trace: FOO ==> I
1. Trace: (FOO I)
1. Trace: FOO ==> I
1. Trace: (FOO I)
1. Trace: FOO ==> I
(0 1 2 3)

LispWorks 是另一个支持宏跟踪的实现。

那么,Common Lisp 中没有任何跟踪宏的工具的原因是什么?

如前所述,这是语言标准。除了语言标准实现之外,还以各种方式提供各种语言扩展,包括一些 Lisp 解释器 (!) 跟踪宏的能力。

如果代码已经编译,则无论如何跟踪都不会起作用。有一个 Lisp 解释器会有所帮助,但实现不需要有一个解释器。这里的 Lisp 解释器是指一个执行引擎,它将 Lisp 代码作为数据工作。

【讨论】:

    【解决方案2】:

    在宏上使用trace 似乎有点奇怪,但它在 CLISP 中有效:

    (trace push)
    (defparameter *stack* '())
    
    (defun push-xy (x y)
      (push x *stack*)
      (push y *stack*))
    ; 1. Trace: (push x *stack*)
    ; 1. Trace: push ==> (setq *stack* (cons x *stack*))
    ; 1. Trace: (push y *stack*)
    ; 1. Trace: push ==> (setq *stack* (cons y *stack*))
    ; ==> push-xy
    

    标准没有说明何时应该扩展宏,因此在定义、编译和有时调用函数和 lambda 时可能会发生这种情况。一些实现运行宏两次,所以你得到双倍的输出。

    我从不使用这个。我宁愿使用macroexpand-1:

    (macroexpand-1 '(push x *stack)))
    ; ==> (setq *stack (cons x *stack))
    ; ==> t
    

    如果您的表单返回一个使用宏的新表单,您可能想尝试使用macroexpand。这就像一遍又一遍地调用macroexpand-1,直到没有任何转换。

    【讨论】:

      【解决方案3】:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-12
        • 1970-01-01
        • 2022-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多