gpt4 book ai didi

scheme - 在 Racket 中的宏扩展期间评估表单

转载 作者:行者123 更新时间:2023-12-02 07:58:14 25 4
gpt4 key购买 nike

这个 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

试图在 Racket 中做到这一点
(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 中时,它可以工作......

我很感激任何帮助!

最佳答案

Racket 有卫生宏。考虑:

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

关于scheme - 在 Racket 中的宏扩展期间评估表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60693402/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com