我在使用Lisp的反引号读取宏时遇到了问题。每当我尝试编写一个似乎需要使用嵌入式反引号的宏(例如来自Paul Graham的《ANSI Common Lisp》第399页的
举个例子,我目前需要一个宏,该宏将以描述规则的形式接受一个表单,规则的形式为
我能提供的最佳翻译如下:
经过评估,SBCL输出以下错误报告:
如何编写宏来生成所需的代码,特别是如何实现
借鉴Ivijay和discipulus的想法,我修改了这个宏,使其能够编译并正常工作,甚至可以将表单作为参数传递。它与我的原始计划有些不同,因为我确定将
此外,希望能够提供一些干净、Lispy的方法来使宏生成代码以在运行时正确地评估参数的解释。
``(w ,x ,,y)
),我就无法弄清楚如何以可以编译的方式编写我的代码。通常,我的代码会接收到一整串错误信息,其中的错误提示为“逗号不在反引号内”。能否有人提供一些指南,告诉我如何编写可以正确评估的代码?举个例子,我目前需要一个宏,该宏将以描述规则的形式接受一个表单,规则的形式为
'(function-name column-index value)
,并生成一个谓词lambda体来确定特定行的由column-index
索引的元素是否满足该规则。如果我使用规则'(< 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的方法来使宏生成代码以在运行时正确地评估参数的解释。
gensym
,去掉eval
,然后就只剩下三行代码,看起来很漂亮,而且运行正确。你甚至可以去掉destructuring-bind
,让它变成两行代码。 - smackcrane