在球拍中进行宏扩展时求值形式

问题描述 投票:0回答:2

此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时,它可以工作...

我非常感谢您的帮助!

scheme lisp racket
2个回答
1
投票

球拍具有卫生宏。考虑:

(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))

0
投票

作为对应的Sorawee Porncharoenwase's answer(这是正确的答案),我认为值得思考一下为什么您的test宏在CL中有问题,以及为什么做类似事情的宏完全是越野车。

© www.soinside.com 2019 - 2024. All rights reserved.