Suz*_*ron 8 metalanguage require racket
我正在尝试在Racket中编写一个模块元语言mylang,它接受第二种语言传递修改后的正文,这样:
(module foo mylang typed/racket body)
Run Code Online (Sandbox Code Playgroud)
相当于:
(module foo typed/racket transformed-body)
Run Code Online (Sandbox Code Playgroud)
当然,typed/racket部件可以用任何其他模块语言替换.
我尝试了一个简单的版本,让身体保持不变.它在命令行上运行正常,但在DrRacket中运行时出现以下错误:
/usr/share/racket/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:479:30: require: namespace mismatch;
reference to a module that is not available
reference phase: 1
referenced module: "/usr/share/racket/pkgs/typed-racket-lib/typed-racket/env/env-req.rkt"
referenced phase level: 0 in: add-mod!
Run Code Online (Sandbox Code Playgroud)
这是整个代码:
#lang racket
(module mylang racket
(provide (rename-out [-#%module-begin #%module-begin]))
(require (for-syntax syntax/strip-context))
(define-syntax (-#%module-begin stx)
(syntax-case stx ()
[(_ lng . rest)
(let ([lng-sym (syntax-e #'lng)])
(namespace-require `(for-meta -1 ,lng-sym))
(with-syntax ([mb (namespace-symbol->identifier '#%module-begin)])
#`(mb . #,(replace-context #'mb #'rest))))])))
(module foo (submod ".." mylang) typed/racket/base
(ann (+ 1) Number))
(require 'foo)
Run Code Online (Sandbox Code Playgroud)
要求(即我宁愿避免的解决方案):
(require (only-in typed/racket))在mylang模块内部添加一个可以使这个工作,但我对一般解决方案感兴趣,在那里mylang不需要知道typed/racketal(即如果有人添加一种新语言foo,那么mylang应该开箱即用).另外,我没有兴趣在声明子模块,并立即技巧require和重新provide它,因为都是在这里完成的,因为这改变了路径实际模块(所以main并test失去其特殊的行为,例如).
它在编译时也比较慢,因为子模块被访问和/或实例化的次数更多(这可以通过编写来看出(begin-for-syntax (displayln 'here)),并且对大型typed/racket程序有明显的影响.
奖励积分,如果在DrRacket工作的箭头由委派到语言,如提供内置插件具有箭头ann,+并Number以typed/racket/base上面的例子.
您可以做的一件事(我认为这不会违反您的要求)是将其放入模块中,完全扩展该模块,然后匹配以#%plain-module-begin插入需求。
#lang racket\n\n(module mylang racket\n (provide (rename-out [-#%module-begin #%module-begin]))\n (define-syntax (-#%module-begin stx)\n (syntax-case stx ()\n [(_ lng . rest)\n (with-syntax ([#%module-begin (datum->syntax #f \'#%module-begin)])\n ;; put the code in a module form, and fully expand that module\n (define mod-stx\n (local-expand\n #\'(module ignored lng (#%module-begin . rest))\n \'top-level\n (list)))\n ;; pattern-match on the #%plain-module-begin form to insert a require\n (syntax-case mod-stx (module #%plain-module-begin)\n [(module _ lng (#%plain-module-begin . mod-body))\n #\'(#%plain-module-begin\n (#%require lng)\n .\n mod-body)]))])))\n\n;; Yay the check syntax arrows work!\n(module foo (submod ".." mylang) typed/racket/base\n (ann (+ 1) Number))\n\n(require \'foo)\nRun Code Online (Sandbox Code Playgroud)\n\n如果你想以某种方式改变身体,你可以在扩张之前或之后进行。
\n\n插入额外内容的模式匹配(#%require lng)是必要的,因为在可用的上下文中扩展模块主体lng是不够的。mod-body从表单中取出代码意味着module绑定将引用lng,但lng在运行时不可用。这就是为什么我在require: namespace mismatch; reference to a module that is not available没有它的情况下收到错误,这就是为什么需要在扩展后添加它。
然而,正如 @GeorgesDup\xc3\xa9ron 在评论中指出的那样,这引入了另一个问题。如果lng提供了一个标识符x,并且使用它的模块导入了一个不同的x,那么就会出现不应该出现的导入冲突。要求行应该位于相对于模块语言的“嵌套范围”中,以便它们可以像x这里一样隐藏标识符。
@GeorgesDup\xc3\xa9ron 在球拍用户列表的这封电子邮件中找到了此问题的解决方案,使用(make-syntax-introducer)来mod-body生成嵌套范围。
(module mylang racket\n (provide (rename-out [-#%module-begin #%module-begin]))\n (define-syntax (-#%module-begin stx)\n (syntax-case stx ()\n [(_ lng . rest)\n (with-syntax ([#%module-begin (datum->syntax #f \'#%module-begin)])\n ;; put the code in a module form, and fully expand that module\n (define mod-stx\n (local-expand\n #\'(module ignored lng (#%module-begin . rest))\n \'top-level\n (list)))\n ;; pattern-match on the #%plain-module-begin form to insert a require\n (syntax-case mod-stx (module #%plain-module-begin)\n [(module _ lng (#%plain-module-begin . mod-body))\n #`(#%plain-module-begin\n (#%require lng)\n .\n #,((make-syntax-introducer) #\'mod-body))]))])))\nRun Code Online (Sandbox Code Playgroud)\n