这可能是一个新手问题,但是我试图编写一个宏来检测标识符是否在宏扩展点上词汇绑定,并相应地更改其输出。这是否可以在R6RS方案中进行,如果是的话,如何?
为什么我想知道
我正在使用宏(Macros)在Chez方案中编写一个玩具Objective-C结合层,而我的最初挑战是有效地处理Objective-C选择器。该程序必须在运行时查询Objective-C运行时,以了解与每个选择器名称相对应的实际SEL
对象。该程序中使用的选择器名称将在静态上以静态为单位,并且在扩展过程中很容易,很容易将我的宏插入该查询代码,但是我想避免对相同的选择器名称重复查询。
我对此的第一个想法是为与 SEL
外来对象绑定的方案定义有一些命名约定。这样,我可以为每个唯一的选择器提供一个(define)
,因此每个选择器都有一个运行时查询。这取决于我的宏能够检测到任何给定选择器的这些绑定,并在它们尚不存在的情况下介绍它们,因此我的问题。
此解决方案仍然不完美,因为我的宏可能会在内部范围内扩展,但这对我来说是最明显的。是否有更好的方法在扩展时"实习"表达式?
我不完全确定是否可以通过指定的行为来实现这一点,但是您可以像以下内容一样做:
#!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个标识符,当宏扩展时,它们都应该取消结合。为了制作这样的未结合标识符,该代码由2个部分,实现和环境组成:第一个是(bound helper)
,它提供了标识符比较的实现。另一个是(bound)
,几乎没有绑定环境。
比较是与要检查的环境库和实际标识符传递的标识符进行的。如果实际标识符绑定到任何事物,那么它将与未结合标识符相同,因此bound?
应返回#f
。(如果定义make-binding-check
并检查,则它将返回#T,因为它在(bound)
库中定义。)
谨慎这可能会根据您正在使用的实施而起作用,也可能不起作用,我不确定这对Chez是否有效。