Macros Racket:`syntax local import`跨模块边界

Macros Racket:`syntax local import`跨模块边界,macros,racket,Macros,Racket,在下面的文件中,宏m2定义了一个标识符foo,并通过语法本地介绍将其提供给用户代码。当随后扩展m1时,(自由标识符=?#'m2-id#'user-id)按预期计算为#t #lang racket (define-syntax (m1 stx) (syntax-case stx () [(_ m2-id user-id) #`#,(free-identifier=? #'m2-id #'user-id)])) (define-syntax (m2 stx) (synt

在下面的文件中,宏
m2
定义了一个标识符
foo
,并通过
语法本地介绍将其提供给用户代码。当随后扩展
m1
时,
(自由标识符=?#'m2-id#'user-id)
按预期计算为
#t

#lang racket

(define-syntax (m1 stx)
  (syntax-case stx ()
    [(_ m2-id user-id)
     #`#,(free-identifier=? #'m2-id #'user-id)]))

(define-syntax (m2 stx)
  (syntax-case stx ()
    [(_ user-id)
     #`(begin (define (foo) 1)
              (m1 foo #,(syntax-local-introduce #'user-id)))]))

(m2 foo) ;; => #t
(m2 foo) ;; => #t
但是,如果我将两个宏包装在一个模块中,
(自由标识符=?#'m2-id#'user-id)
的计算结果为
\f

为什么会这样

当宏在单独的模块中定义时,如何解决此问题并获得第一个示例的行为

请注意,我希望能够多次执行宏,因此使用
(define(#,(datum->syntax stx'foo))1
不是一个选项,因为当两次调用宏时,这将导致定义冲突

我尝试使用
((make syntax delta introductor#'foo#'user-id)#'user-id)
而不是
,(syntax local introduct#'user-id)
,但它也不起作用

我正在使用的实际代码 以下是(伪代码)我正在编写的实际代码:

(define-syntax (define* stx)
  ... expand types, uses free-identifier=? ...)

(define-syntax (define-function-group stx)
    (syntax-parse stx
      [(_ ((~literal defun) (f-name arg ...) ret-type body) ...)
       #`(begin (define-type-expander (return-type-of stx)
                  (syntax-parse stx
                    [(_ (~literal f-name)) #'ret-type] ...))
                (define* (f-name arg ...) : ret-type
                  body) ...)]))

;; defines a type expander "return-type-of"
(define-function-group
  (defun (f1) (Listof String) '("a" "b"))
  (defun (f2 [a : (return-type-of f1)] (length '("a" "b")))))

;; defines another type expander "return-type-of"
(define-function-group etc.)

其中
define-type-expander
来自我的类型扩展器库,工作方式类似于匹配扩展器(我应该在某个时候打包它,但它仍然需要一些工作)
define*
(对应于上面的
m1
)是扩展类型的
define*
的一个变体,它在某个点上使用
free identifier=?
来找到正确的类型扩展定义<代码>定义函数组(与上面的
m2
相对应)允许使用
(某个函数名称的返回类型)
引用另一个函数的返回类型。问题是,每次调用
定义函数组
都会引入一个新的
返回类型
,因此它需要有宏的作用域以避免冲突。

可能有一种更卫生的方法,但这就是我想到的:

你说<代码>数据>语法<代码>不是一个选项,但请考虑以下内容:

(define-syntax (m2 stx)
    (syntax-case stx ()
      [(_ user-id)
       (with-syntax ([foo (syntax-local-introduce (datum->syntax stx 'foo))])
       #`(begin (define (foo) 1)
                (m1 foo #,(syntax-local-introduce #'user-id))))]))

在使用
datum->syntax
的同时,它还将使用站点范围添加到
foo
,使标识符对于每个宏扩展都是唯一的。如果在示例代码中用上述代码替换
m2
,则一切都会按预期运行(并且,正如您所预测的,删除
syntax local incroduct
会导致重复的定义错误)。

我承认,我对这试图解决的问题感到相当困惑。您希望传入的标识符是另一个无关标识符的
自由标识符=?
?我不明白这段代码的目的是什么,我闻到了一种潜在的味道。@AlexisKing我为我的真实用例添加了伪代码。我知道
语法参数化
在这里是一个很好的解决方案,但它会导致其他问题(我隐约怀疑我的类型扩展器库中存在一些怪癖)。
(define-syntax (m2 stx)
    (syntax-case stx ()
      [(_ user-id)
       (with-syntax ([foo (syntax-local-introduce (datum->syntax stx 'foo))])
       #`(begin (define (foo) 1)
                (m1 foo #,(syntax-local-introduce #'user-id))))]))