gpt4 book ai didi

macros - 在 guile 方案中,如何防止从另一个宏调用宏时重命名?

转载 作者:行者123 更新时间:2023-12-04 10:53:17 26 4
gpt4 key购买 nike

; Having this definition that creates identifier `self'
(define-syntax alambda
(lambda (stx)
(syntax-case stx ()
[(alambda lambda-list . body)
(with-syntax ([name (datum->syntax #'alambda 'self)])
#'(letrec ([name (lambda lambda-list . body)])
name))])))

; I want to "compose" it with another macro
(define-syntax-rule [apply-alambda args argv . body]
((alambda args . body) . argv))

; But then it doesn't work (while alambda itself does)
(apply-alambda [x] [5] (if (= 0 x) 1 (* x (self (- x 1)))))
; => Unbound variable: self
; (expected 120)


如何预防 apply-alambda从重命名 self ?

我尝试使用 define-macro这也不起作用,但出于不同的原因:

(defmacro apply-alambda [args argv . body]
((alambda args . body) . argv))
; => lambda: bad lambda in form (lambda args . body)

在这里,我什至不知道出了什么问题

最佳答案

您的 alambda宏是不卫生的,不卫生的宏组合不好。基于已用于其他目的的子术语创建标识符的不卫生宏的组合尤其糟糕。一种解决方案是创建一个辅助宏,它将新标识符的“词法上下文”作为单独的参数。然后从中创建派生的宏。

(define-syntax alambda/lctx
(lambda (stx)
(syntax-case stx ()
[(alambda lctx formals . body)
(with-syntax ([name (datum->syntax #'lctx 'self)])
#'(letrec ([name (lambda formals . body)])
name))])))

(define-syntax alambda
(lambda (stx)
(syntax-case stx ()
[(alambda formals . body)
#'(alambda/lctx alambda formals . body)])))

(define-syntax apply-alambda
(lambda (stx)
(syntax-case stx ()
[(apply-alambda formals argv . body)
#'((alambda/lctx apply-alambda formals . body) . argv)])))

(apply-alambda [x] [5] (if (= 0 x) 1 (* x (self (- x 1)))))

alambda宏,用于创建 self 的词汇上下文binder 取自对宏本身的引用。宏在对 alambda/lctx 的调用中使该参数显式化。 . apply-alambda 也是如此---如果您想创建另一个扩展为 apply-alambda 的宏, 那么你同样应该创建一个 apply-alambda/lctx helper 。

(在 Racket 中,词法上下文不仅附加到标识符,还附加到列表结构(“括号”),不卫生的宏通常使用整个语法对象,如 (datum->syntax stx 'self)。这避免了需要一个单独的辅助宏。)

注意:使用 define-syntax-rule定义 alambdaapply-alambda不起作用,因为它实际上并没有将标识符绑定(bind)在运算符位置。

您可能会想制作 apply-alambda调用 alambdaalambda具有与 apply-alambda 的使用相对应的词汇上下文的标识符形式,像这样:
(define-syntax bad-apply-alambda
(lambda (stx)
(syntax-case stx ()
[(apply-alambda formals argv . body)
(with-syntax ([alambda (datum->syntax #'apply-alambda 'alambda)])
#'((alambda formals . body) . argv))])))

这个版本是错误的。如果 alambda 则行为不正确在 bad-apply-alambda 的范围内未绑定(bind)(或绑定(bind)到错误的事物)用来。例如:
(let ([alambda 5])
(bad-apply-alambda [x] [5] (if (= 0 x) 1 (* x (self (- x 1))))))

关于macros - 在 guile 方案中,如何防止从另一个宏调用宏时重命名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59357931/

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