检查标识符是否在宏扩展点词法绑定?

Check if an identifier is lexically bound at the point of macro expansion?

这可能是个新手问题,但我正在尝试编写一个宏来检测标识符是否在宏扩展点词法绑定,并相应地更改其输出。这在 R6RS 方案中是否可行,如果可行,如何实现?

为什么我想知道

我正在 Chez Scheme 中使用宏编写玩具 Objective-C 绑定层,我最初的挑战是有效地处理 Objective-C 选择器。程序必须在运行时查询 Objective-C 运行时,以获取与每个选择器名称对应的实际 SEL 对象。程序中使用的选择器名称在扩展期间将是静态已知的,并且很容易让我的宏插入该查询代码,但我想避免重复查询相同的选择器名称。

我的第一个想法是为绑定到 SEL 外部对象的 Scheme 定义制定一些命名约定。这样,我可以为每个唯一选择器设置一个 (define),因此每个选择器都有一个运行时查询。这取决于我的宏能够检测任何给定选择器的这些绑定,并在它们尚不存在时引入它们,因此我的问题。

这个解决方案仍然不完善,因为我的宏可能会在内部范围内扩展,但这对我来说是最明显的。有没有更好的方法在扩展时 "intern" 表达式?

我不完全确定这是否可以通过指定的行为来实现,但你可以像下面这样:

#!r6rs
(library (bound helper)
    (export make-binding-check)
    (import (rnrs))
(define-syntax make-binding-check
  (lambda (x)
    (syntax-case x ()
      ((_ if bound?)
       #'(begin
           (define-syntax if
             (lambda (xx)
               (syntax-case xx ()
                 ((_ b then els)
                  (free-identifier=? (datum->syntax #'if (syntax->datum #'b)) #'b)
                  #'els)
                 ((_ b then els)
                  #'then))))
           (define-syntax bound?
             (lambda (xx)
               (syntax-case xx ()
                 ((_ b)
                  #'(if b #t #f))))))))))
)
(library (bound)
    (export bound? if-bound)
    (import (bound helper))
(make-binding-check if-bound bound?)
)

(import (rnrs) (bound))

(display (bound? foo)) ;; #f
(let ((foo 1))
  (display (bound? foo))) ;; #t
(newline)

这个想法是使用 free-identifier=? 检查给定的标识符是否已绑定。 make-binding-check 宏有 2 个标识符,当宏被扩展时,它们都应该被解除绑定。为了制作这样的未绑定标识符,代码由两部分组成,实现和环境:第一个是 (bound helper),它提供了标识符比较的实现。另一个是 (bound) ,它几乎不提供任何绑定环境。

比较是通过从环境库传递的标识符和您要检查的实际标识符完成的。如果实际标识符绑定到任何东西,那么它就不会与未绑定的标识符相同,因此 bound? 应该 return #f。 (如果您定义 make-binding-check 并检查,它会 return #t 因为它是在 (bound) 库中定义的。)

注意 这可能有效,也可能无效,具体取决于您使用的实施方式,我不确定这是否适用于 Chez。