我在使用 Lisp 的反引号读取宏时遇到问题。每当我尝试编写一个似乎需要使用嵌入式反引号的宏时(例如,``(w ,x ,,y)
来自 Paul Graham 的ANSI Common Lisp,第 399 页),我都无法弄清楚如何以可编译的方式编写我的代码。通常,我的代码会收到一整串以“逗号不在反引号内”开头的错误。有人可以为我如何编写能够正确评估的代码提供一些指导吗?
例如,我目前需要一个宏,它采用一种描述规则的形式,'(function-name column-index value)
并生成一个谓词 lambda 主体,以确定column-index
特定行的索引元素是否满足规则。如果我用 rule 调用这个宏'(< 1 2)
,我希望生成一个如下所示的 lambda 主体:
(lambda (row)
(< (svref row 1) 2))
我能做出的最好的尝试如下:
(defmacro row-satisfies-rule (rule)
(let ((x (gensym)))
`(let ((,x ,rule))
(lambda (row)
(`,(car ,x) (svref row `,(cadr ,x)) `,(caddr ,x))))))
评估后,SBCL 会发出以下错误报告:
; in: ROW-SATISFIES-RULE '(< 1 2)
; ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121))
;
; caught ERROR:
; illegal function call
; (LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121)))
; ==>
; #'(LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121)))
;
; caught STYLE-WARNING:
; The variable ROW is defined but never used.
; (LET ((#:G1121 '(< 1 2)))
; (LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121))))
;
; caught STYLE-WARNING:
; The variable #:G1121 is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 2 STYLE-WARNING conditions
#<FUNCTION (LAMBDA (ROW)) {2497F245}>
如何编写宏来生成我需要的代码,特别是如何实现row-satisfies-rule
?
使用 Ivijay 和 discipulus 的想法,我修改了宏,使其可以编译和工作,甚至允许将表单作为参数传递。它的运行方式与我最初计划的宏有点不同,因为我确定将其row
作为参数包含在内以使代码更流畅。然而,它像罪恶一样丑陋。有谁知道如何清理它,以便它在没有调用的情况下执行相同的操作eval
?
(defmacro row-satisfies-rule-p (row rule)
(let ((x (gensym))
(y (gensym)))
`(let ((,x ,row)
(,y ,rule))
(destructuring-bind (a b c) ,y
(eval `(,a (svref ,,x ,b) ,c))))))
此外,非常感谢解释干净的 Lispy 方法来获取宏以生成代码以在运行时正确评估参数。