此Common Lisp宏和测试功能
(defmacro test (body)
`(let ,(mapcar #'(lambda (s)
`(,s ,(char-code (char-downcase (char (symbol-name s) 0)))))
'(a b))
,body))
(test (+ a b))
展开为
(let ((a 97) (b 98))
(+ a b))
并在评估时给出195
尝试在球拍中这样做
(define-syntax (test stx)
(syntax-case stx ()
[(_ body)
#`(let #,(map (lambda (x)
(list x
(char->integer (car (string->list (symbol->string x))))))
'(a b))
body)]))
(test (+ a b))
当我运行宏扩展器时,宏形式扩展为:
(let ((a 97) (b 98)) (+ a b))))
这就是我想要的。
但是失败了:
a: unbound identifier in context..
禁用宏隐藏将给出以以下形式结尾的形式:
(#%app:35
call-with-values:35
(lambda:35 ()
(let-values:36 (((a:37) (quote 97)) ((b:37) (quote 98)))
(#%app:38 + (#%top . a) b)))
(print-values:35)))
我不明白为什么我的扩展名(let ((a 97) (b 98)) (+ a b))
不能正常工作,并且我对(#%top .a)感到困惑...我想知道它是否正在尝试找到一个名为“ a”的函数?当我将展开的表单复制到REPL时,它可以工作...
我非常感谢您的帮助!
球拍具有卫生宏。考虑:
(define-syntax-rule (or a b)
(let ([a-val a])
(if a-val a-val b)))
然后:
(let ([a-val 1])
(or #f a-val))
将大致扩展为:
(let ([a-val 1])
(let ([a-val2 #f])
(if a-val2 a-val2 a-val)))
其值为1
。如果宏不卫生,则将导致#f
,这被认为是不正确的。
注意,a-val
自动重命名为a-val2
,以避免发生冲突。您的案件也是如此。
解决您的问题的一种方法是为生成的标识符提供正确的上下文,以便宏扩展程序理解它们应该引用相同的变量。]>
(define-syntax (test stx)
(syntax-case stx ()
[(_ body)
#`(let #,(map (lambda (x)
(list (datum->syntax stx x) ; <-- change here
(char->integer (car (string->list (symbol->string x))))))
'(a b))
body)]))
(test (+ a b))
作为对应的Sorawee Porncharoenwase's answer(这是正确的答案),我认为值得思考一下为什么您的test
宏在CL中有问题,以及为什么做类似事情的宏完全是越野车。