将let字符串值传入Lisp宏时提示非字符串类型的问题排查
Lisp宏参数传递错误排查与解决
问题描述
我尚未完全理解宏接收参数的机制,以下代码中:
(macroexpand-1 (let ((des "des")) '(defhomepage (:title "hi" :description des :canonical "can" ))))
我期望将值"des"直接传入defhomepage宏,并且在defhomepage宏内部设置了类型检查:
(defmacro defhomepage ((&key :title :description :canonical)) (check-type description string) ... ... )
但收到错误提示,称des不是字符串类型,请问哪里操作有误?
问题核心
你用单引号'(等价于(quote ...))包裹defhomepage调用,这会让整个表达式原样传递给宏,不会对内部的des变量求值。也就是说,宏收到的:description参数不是字符串"des",而是符号des,这自然通不过check-type的字符串类型检查。
解决方案
要让des变量在宏展开前先求值,需使用反引号(`)配合逗号(,)实现“准引用”,标记需要求值的部分:
(macroexpand-1 (let ((des "des")) `(defhomepage (:title "hi" :description ,des :canonical "can" ))))
反引号会保留表达式结构,逗号则指定该位置的变量需要先求值再传入宏,这样宏收到的:description参数就是des的实际值"des",就能通过类型检查了。
补充说明
宏运行在编译期,操作的是代码的抽象语法树(AST),而非运行时的值。你原写法中,des是运行时变量,但单引号让它以符号形式传入宏,宏在编译期只能看到符号des,而非其运行时值,因此类型检查失败。反引号+逗号的组合可以将运行时值提前注入到宏的参数中,解决这个问题。
内容的提问来源于stack exchange,提问作者Vinn
相关产品推荐
相关产品推荐

