Common Lisp Lisp-1宏

时间:2015-01-14 20:37:47

标签: macros common-lisp lisp-2

我试图在普通的lisp中模拟方案的单个命名空间,其中宏(基于Doug Hoyte' s)扩展为lambda,每次使用f!符号(类似于函数位置中的Doug Hoyte的o!g!符号)扩展为相同的表达式,但在每次调用的函数位置添加了funcall。例如:

(fplambda (f!z x) (f!z x x))

将扩展为:

(LAMBDA (F!Z X) (FUNCALL F!Z X X))

宏目前看起来像这样:

(defmacro fplambda (parms &body body)
  (let ((syms (remove-duplicates
                (remove-if-not #'f!-symbol-p
                               (flatten body)))))
    `(lambda ,parms
       (macrolet ,(mapcar
               (lambda (f)
                 `(,f (&rest parmlist)  `(funcall ,',f ',@parmlist)))
               syms))
         ,@body)))

但是考虑到上面的输入,它会扩展(据我所见):

(LAMBDA (F!F X)
       (MACROLET ((F!F (&REST PARMLIST) `(FUNCALL ,'F!F ',@PARMLIST))))
       (F!F X X))

在macrolet定义中,不应引用或不引用F!F,并且parmlist应该是不加引号的。到底是怎么回事? 提前谢谢!

1 个答案:

答案 0 :(得分:4)

你的定义大多是正确的。你刚刚犯了两个非常简单的错误。第一个是不匹配的paren。 macrolet不包括body(在输出中,macrolet和body处于相同的缩进级别)。

至于嵌套的反引号,唯一的错误是parmlist之前的引用。除此之外,其他一切都是正确的。 F!F之前的逗号和引号实际上是正确的。来自hyperspec: “一个实现可以自由地将反引号形式F1解释为任何形式F2,在评估时,它将产生与上述定义所暗示的结果相同的结果”。由于内部反引用尚未扩展,因此它不必没有引号和引号。表达式`(,'x)实际上与`(x)相同。

嵌套的反引号非常复杂。理解它们的最简单方法可能是阅读Steele's explanation of them

编辑:

关于是否可以在函数位置使用fplambda表达式的问题的答案是否定的。从hyperspec that deals with the evaluation of code的部分:“如果复合形式的汽车不是符号,则该汽车必须是lambda表达式,在这种情况下,复合形式是lambda形式。”由于表单的汽车(fplambda ...)不是lambda表达式,因此您的代码不再是有效的Common Lisp代码。

我想出了一个解决方法,但它有点难看。您可以定义一个reader macro,它允许您编写类似([fplambda ...] ...)的内容,并将其读作

((LAMBDA (&REST #:G1030) (APPLY (FPLAMBDA ...) #:G1030)) ...)

哪会做你想要的。以下是允许您执行此操作的代码:

(set-macro-character #\[ 'bracket-reader)
(set-macro-character #\] (get-macro-character #\)))

(defun bracket-reader (stream char)
  "Read in a bracket."
  (declare (ignore char))
  (let ((gargs (gensym)))
    `(lambda (&rest ,gargs) 
       (apply ,(read-delimited-list #\] stream t)
              ,gargs))))

我能想到的唯一其他解决方案是使用某种代码行走器(我无法帮助你)。