1

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

为什么我想知道

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

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

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

4

1 回答 1

1

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

#!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=?用来检查给定的标识符是否被绑定。宏需要 2 个标识符,make-binding-check当宏展开时,它们都应该是未绑定的。为了制作这样的未绑定标识符,代码由两部分组成,实现和环境:第一个是(bound helper)提供标识符比较的实现。另一种是(bound)几乎不提供绑定环境。

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

注意 这可能会也可能不会根据您使用的实现而起作用,我不确定这是否适用于 Chez。

于 2017-12-18T20:38:14.450 回答