1

我正在尝试在 common lisp 中模拟方案的单个命名空间,并使用扩展为 lambda 的宏(基于 Doug Hoyte),其中函数位置中f!符号(类似于 Doug Hoyteo!和符号)的每次使用都会扩展为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))

在宏定义中,F!F 不应该被引用或不被引用,而 parmlist 应该只是不被引用。到底是怎么回事?提前致谢!

4

1 回答 1

4

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

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

嵌套反引号非常复杂。理解它们的最简单方法可能是阅读斯蒂尔对它们的解释

编辑:

关于是否可以在函数位置使用 fplambda 表达式的问题的答案是否定的。来自处理代码评估的超规范部分:“如果复合形式的汽车不是符号,那么该汽车必须是 lambda 表达式,在这种情况下复合形式是 lambda 形式。”。由于 (fplambda ...) 形式的 car 不是 lambda 表达式,因此您的代码不再是有效的 Common Lisp 代码。

我想出了一个解决方法,但这有点难看。您可以定义一个阅读器宏,它允许您编写类似 ([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))))

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

于 2015-01-14T21:47:37.067 回答