Common Lisp Lisp-1 宏
Common Lisp Lisp-1 macro
我正在尝试在普通 lisp 中模拟 scheme 的单个命名空间,使用扩展为 lambda 的宏(基于 Doug Hoyte 的),其中每次使用 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 应该被不被引用。到底是怎么回事?
提前致谢!
您的定义基本正确。你刚刚犯了两个非常简单的错误。第一个是不匹配的父母。 macrolet 不包含正文(在输出中,macrolet 和正文处于同一缩进级别)。
至于嵌套的反引号,唯一的错误是parmlist之前的引号。除此之外,其他一切都是正确的。 F!F 之前的逗号和引号实际上是正确的。来自 hyperspec:
"An implementation is free to interpret a backquoted form F1 as any form F2 that, when evaluated, will produce a result that is the same under equal as the result implied by the above definition"。由于内部反引号尚未扩展,因此它不必没有引号和反引号。表达式 `(,'x) 实际上等同于 `(x).
众所周知,嵌套反引号非常复杂。理解它们的最简单方法可能是阅读 Steele's explanation of them.
编辑:
关于是否可以在函数位置使用 fplambda 表达式的问题,答案是否定的。来自hyperspec that deals with the evaluation of code的部分:"If the car of the compound form is not a symbol, then that car must be a lambda expression, in which case the compound form is a lambda form."。由于形式 (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))))
我能想到的唯一其他解决方案是使用某种代码遍历器(我帮不了你)。
我正在尝试在普通 lisp 中模拟 scheme 的单个命名空间,使用扩展为 lambda 的宏(基于 Doug Hoyte 的),其中每次使用 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 应该被不被引用。到底是怎么回事? 提前致谢!
您的定义基本正确。你刚刚犯了两个非常简单的错误。第一个是不匹配的父母。 macrolet 不包含正文(在输出中,macrolet 和正文处于同一缩进级别)。
至于嵌套的反引号,唯一的错误是parmlist之前的引号。除此之外,其他一切都是正确的。 F!F 之前的逗号和引号实际上是正确的。来自 hyperspec: "An implementation is free to interpret a backquoted form F1 as any form F2 that, when evaluated, will produce a result that is the same under equal as the result implied by the above definition"。由于内部反引号尚未扩展,因此它不必没有引号和反引号。表达式 `(,'x) 实际上等同于 `(x).
众所周知,嵌套反引号非常复杂。理解它们的最简单方法可能是阅读 Steele's explanation of them.
编辑:
关于是否可以在函数位置使用 fplambda 表达式的问题,答案是否定的。来自hyperspec that deals with the evaluation of code的部分:"If the car of the compound form is not a symbol, then that car must be a lambda expression, in which case the compound form is a lambda form."。由于形式 (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))))
我能想到的唯一其他解决方案是使用某种代码遍历器(我帮不了你)。