我试图在普通lisp中模拟方案的单个名称空间,使用一个宏(基于Doug的宏)扩展为lambda,其中函数位置中的f!符号(类似于Doug的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))在宏定义中,F!F不应该被引用或不引用,而parmlist不应该被引用。怎么一回事?提前感谢!
发布于 2015-01-14 21:47:37
你的定义基本上是对的。你刚刚犯了两个很简单的错误。第一个是不匹配的帕伦。宏不包括主体(在输出中,宏和主体处于相同的缩进水平)。
至于嵌套的反向引用,唯一的错误是在parmlist之前的引用。除此之外,其他的一切都是正确的。F!F之前的逗号和引号实际上是正确的。在超石化中:“实现可以自由地将反引用的表单F1解释为任何表单F2,该表单F2在计算时将产生与上述定义所暗示的结果相同的结果”。由于内部引号还没有被扩展,它不需要没有引号和引号。表达式(,'x) is actually the same as(x)。
嵌套的反引号是众所周知的复杂。理解它们的最简单的方法可能是阅读斯蒂尔对他们的解释。
编辑:
对于在函数位置上是否可以使用fplambda表达式的问题,答案是否定的。从处理代码计算的hyperspec的部分:“如果复合表单的car不是符号,那么该car必须是lambda表达式,在这种情况下,复合表单是lambda形式。”因为表单的car (fplambda .)不是lambda表达式,所以您的代码不再是有效的Common代码。
有个解决办法,我想出来了,但它有点丑。您可以定义一个读取器宏,它允许您编写类似于(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))))我唯一能想到的其他解决方案是使用某种代码遍历器(我无法在那里帮助您)。
https://stackoverflow.com/questions/27951972
复制相似问题