完全展开宏窗体

时间:2013-05-16 05:48:26

标签: macros lisp common-lisp

我想学习Lisp的内部,所以我想看看一切是如何实现的。

例如,

(macroexpand '(loop for i upto 10 collect i))

给了我(在SBCL中)

(BLOCK NIL
  (LET ((I 0))
    (DECLARE (TYPE (AND NUMBER REAL) I))
    (SB-LOOP::WITH-LOOP-LIST-COLLECTION-HEAD (#:LOOP-LIST-HEAD-1026
                                              #:LOOP-LIST-TAIL-1027)
      (SB-LOOP::LOOP-BODY NIL
                          (NIL NIL (WHEN (> I '10) (GO SB-LOOP::END-LOOP)) NIL)
                          ((SB-LOOP::LOOP-COLLECT-RPLACD
                            (#:LOOP-LIST-HEAD-1026 #:LOOP-LIST-TAIL-1027)
                            (LIST I)))
                          (NIL (SB-LOOP::LOOP-REALLY-DESETQ I (1+ I))
                           (WHEN (> I '10) (GO SB-LOOP::END-LOOP)) NIL)
                          ((RETURN-FROM NIL
                             (SB-LOOP::LOOP-COLLECT-ANSWER
                              #:LOOP-LIST-HEAD-1026)))))))

但是LOOP-BODY,WITH-LOOP-LIST-COLLECTION-HEAD等仍然是宏。如何完全展开宏窗体?

4 个答案:

答案 0 :(得分:15)

要查看完整扩展,需要在所有级别上遍历Lisp表单并展开它们。为此,这个所谓的代码漫游器必须理解Lisp语法(而不仅仅是s表达式语法)。例如,在(lambda (a b) (setf a b))中,列表(a b)是参数列表,不应进行宏扩展。

各种Common Lisp实现提供了这样的工具。 6502的回答提到了MACROEXPAND-ALL由SBCL提供。

如果您使用开发环境,它通常作为命令提供:

  • SLIME: M-x slime-macroexpand-all C-c M-m

  • LispWorks:menu Expression > 步行 M-x Walk Form ,更短 M-Sh-m

答案 1 :(得分:10)

其他答案对你来说非常好,但你说你想看看一切是如何实现的。

许多宏(如您所知)已经使用宏实现,而 macroexpand-all 非常有用,但是您可能会丢失宏负责什么更改的上下文。

一个不错的中间地带(如果你使用粘液)是使用 slime-expand-1 (C-c Enter),它显示扩展是另一个缓冲区。然后,您可以在此新缓冲区中使用 slime-expand-1 来就地扩展宏。 这允许您在阅读时遍历树扩展,并使用undo再次关闭扩展。

对我而言,这是了解其他人的宏的神灵。希望这对你有所帮助,玩得开心!

答案 2 :(得分:3)

您可以尝试使用MACROEXPAND-ALL,但您可能获得的并不一定有用。

在像LOOP之类的东西中,真正的肉是宏本身,而不是生成的代码。

答案 3 :(得分:1)

(注意:如果你对便携性不感兴趣,SBCL会提供macroexpand-all,这将完成您所追求的目标。如果您正在使用便携式解决方案,请继续阅读......)

快速和肮脏的解决方案是macroexpand表单本身,然后递归macroexpand除了结果列表的第一个元素。这是一个不完美的解决方案;它会在尝试处理let的绑定时完全失败(let的第一个参数,绑定列表,并不是宏扩展,但是这个代码无论如何都会这样做)

;;; Quick-and-dirty macroexpand-all
(defun macroexpand* (form)
  (let ((form (macroexpand form)))
    (cons (car form) (mapcar #'macroexpand (cdr form)))))

更完整的解决方案会特别考虑特殊形式,而不是宏观扩展其未评估的论点。如果需要,我可以使用这样的解决方案进行更新。