Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros 完全展开宏窗体_Macros_Lisp_Common Lisp - Fatal编程技术网

Macros 完全展开宏窗体

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

我想学习Lisp的内部结构,所以我想看看每件事情是如何实现的

比如说,

(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)))))