【问题标题】:Check if an identifier is lexically bound at the point of macro expansion?检查标识符是否在宏扩展点被词法绑定?
【发布时间】:2017-12-18 05:39:56
【问题描述】:

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

为什么我想知道

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

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

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

【问题讨论】:

    标签: macros scheme r6rs chez-scheme


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

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

    注意 这可能会也可能不会起作用,具体取决于您使用的实现,我不确定这是否适用于 Chez。

    【讨论】:

      猜你喜欢
      • 2017-11-16
      • 2020-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      相关资源
      最近更新 更多