我正在尝试在 Racket 中编写一个模块 meta-language mylang
,它接受将修改后的主体传递给的第二种语言,例如:
(module foo mylang typed/racket body)
相当于:
(module foo typed/racket transformed-body)
当然,该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!
这是整个代码:
#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)
要求(即我宁愿避免的解决方案):
(require (only-in typed/racket))
在模块内部添加一个mylang
可以使这项工作,但我对一个通用的解决方案感兴趣,mylang
根本不需要知道typed/racket
(即如果有人添加了一种新语言foo
,那么mylang
应该开箱即用)。此外,我对声明子模块并立即
require
重新声明子模块的技巧不感兴趣provide
,就像这里所做的那样,因为这会改变到实际模块的路径(例如,因此会main
失去test
它们的特殊行为)。它在编译时也更慢,因为子模块被访问和/或实例化的次数更多(这可以通过编写来看到,并且对大型程序
(begin-for-syntax (displayln 'here))
有明显的影响。typed/racket
如果 DrRacket 中的箭头适用于委托语言提供的内置功能,例如在上面的示例中具有来自和to的箭头
ann
,则可以加分。+
Number
typed/racket/base