Macros 完全展开宏窗体
我想学习Lisp的内部结构,所以我想看看每件事情是如何实现的 比如说,Macros 完全展开宏窗体,macros,lisp,common-lisp,Macros,Lisp,Common Lisp,我想学习Lisp的内部结构,所以我想看看每件事情是如何实现的 比如说, (macroexpand '(loop for i upto 10 collect i)) 给我(在SBCL中) 但LOOP-BODY、WITH-LOOP-LIST-COLLECTION-HEAD等仍然是宏。如何完全展开宏窗体?您可以尝试使用MACROEXPAND-ALL,但您可能得到的并不一定有用 在类似于LOOP的情况下,真正重要的是宏本身,而不是生成的代码。(注意:如果您对可移植性不感兴趣,SBCL提供macroex
(macroexpand '(loop for i upto 10 collect i))
给我(在SBCL中)
但LOOP-BODY、WITH-LOOP-LIST-COLLECTION-HEAD等仍然是宏。如何完全展开宏窗体?您可以尝试使用
MACROEXPAND-ALL
,但您可能得到的并不一定有用
在类似于LOOP
的情况下,真正重要的是宏本身,而不是生成的代码。(注意:如果您对可移植性不感兴趣,SBCL提供macroexpand all
,它将完成您所追求的任务。如果您追求的是可移植解决方案,请继续阅读……)
快速而肮脏的解决方案是macroexpand
表单本身,然后递归地macroexpand
除了结果列表的第一个元素之外的所有元素。这是一个不完美的解决方案;当它试图处理let
的绑定时,它将完全失败(绑定列表let
的第一个参数并不意味着要进行宏扩展,但这段代码无论如何都会这样做)
一个更完整的解决方案会特别考虑特殊形式,而不是大规模扩展他们未经评估的论点。如果需要,我可以使用这样的解决方案进行更新。要查看完整的扩展,需要在所有级别上遍历Lisp表单并进行扩展。为此,有必要让这个所谓的代码行者理解Lisp语法(而不仅仅是s表达式语法)。例如,在
(lambda(ab)(setf a b))
中,列表(ab)
是一个参数列表,不应进行宏扩展
各种常见的Lisp实现都提供了这样的工具。6502的答案提到了SBCL提供的MACROEXPAND-ALL
如果使用开发环境,它通常作为命令提供:
- 粘液:M-x粘液宏观膨胀全部含C-C M-M
- LispWorks:菜单表达式>漫游或M-x漫游形式,简称M-Sh-M
- 其他答案非常适合你的问题,但你说你想看看每件事是如何实现的
许多宏(如您所知)都是使用宏实现的,虽然macroexpand all非常有用,但您可能会丢失宏负责什么更改的上下文
一个很好的中间立场(如果您使用slime)是使用slime-expand-1(C-C Enter),这表明扩展是另一个缓冲区。然后,您可以在此新缓冲区内使用slime-expand-1就地展开宏。
这允许您在阅读时遍历展开的树,还可以使用“撤消”再次关闭展开
对我来说,这是上帝派来理解别人的宏指令的。希望这也能帮助你,玩得开心 这是一个很好的方法。Slimv也有这个工作流,仅供vim+lisp用户参考。当考虑可移植性时,请尝试John Fremlin的macroexpand dammit,它在SBCL之外工作,并做同样的事情(尽管macrolet定义显然被progn替换为不需要的)。
(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)))))))
;;; Quick-and-dirty macroexpand-all
(defun macroexpand* (form)
(let ((form (macroexpand form)))
(cons (car form) (mapcar #'macroexpand (cdr form)))))