Macros 使用Racket进行语言扩展,通过宏定义辅助函数
我已经被一个问题困扰了好几个小时了。我正在尝试使用Racket的语言扩展功能定义DSL。我想做一些类似以下伪代码的事情。最终,我想在DSL中生成函数和宏,这些函数和宏中的大部分现在似乎都可以工作了,问题在于提供的定义应该与声明在同一级别上工作。这可能吗?时间不早了,我肯定我错过了一些非常琐碎的事情。这个问题最基本的例子是: tinylang.rkt:Macros 使用Racket进行语言扩展,通过宏定义辅助函数,macros,racket,language-extension,Macros,Racket,Language Extension,我已经被一个问题困扰了好几个小时了。我正在尝试使用Racket的语言扩展功能定义DSL。我想做一些类似以下伪代码的事情。最终,我想在DSL中生成函数和宏,这些函数和宏中的大部分现在似乎都可以工作了,问题在于提供的定义应该与声明在同一级别上工作。这可能吗?时间不早了,我肯定我错过了一些非常琐碎的事情。这个问题最基本的例子是: tinylang.rkt: #lang racket ; here we redefine module begin. (provide (all-defined-out)
#lang racket
; here we redefine module begin.
(provide (all-defined-out)
(except-out (all-from-out racket) #%module-begin)
(rename-out [module-begin #%module-begin])
)
(define-syntax (module-begin stx)
(syntax-case stx ()
[(_ stmts ...)
#`(#%module-begin
(define (hello) (print "Yes!") (newline))
; (provide (for-syntax hello))
(print "Function defined.")
stmts ... )]))
#lang s-exp "tinylang.rkt"
(hello)
现在我尝试在其他地方使用这种新语言:
try.rkt:
#lang racket
; here we redefine module begin.
(provide (all-defined-out)
(except-out (all-from-out racket) #%module-begin)
(rename-out [module-begin #%module-begin])
)
(define-syntax (module-begin stx)
(syntax-case stx ()
[(_ stmts ...)
#`(#%module-begin
(define (hello) (print "Yes!") (newline))
; (provide (for-syntax hello))
(print "Function defined.")
stmts ... )]))
#lang s-exp "tinylang.rkt"
(hello)
但是在加载第二个模块时,我得到了错误“hello:unboundidentifier in module in:hello” 问题在于
hello
是在tinylang.rkt
的词法范围内定义的,但您希望它在try.rkt
的范围内。可以使用设置一段语法的词法上下文
这将解决问题:
#lang racket
; here we redefine module begin.
(provide (all-defined-out)
(except-out (all-from-out racket) #%module-begin)
(rename-out [module-begin #%module-begin])
)
(define-syntax (module-begin stx)
(syntax-case stx ()
[(_ stmts ...)
#`(#%module-begin
#,(datum->syntax
stx
(syntax->datum
#'(define (hello) (print "Yes!") (newline))))
(print "Function defined.")
stmts ... )]))
更新:
根据评论意见,先前的解决方案可以简化为:
(define-syntax (module-begin stx)
(syntax-case stx ()
[(_ stmts ...)
(with-syntax ([hello-fn (datum->syntax stx 'hello)])
#`(#%module-begin
(define (hello-fn) (print "Yes!") (newline))
(print "Function defined.")
stmts ... ))]))
你也会发现这篇文章很有用。谢谢@stchange,我看到了那篇帖子,它实际上帮助了我开始这个项目。这个
(语法->数据)
部分可以简单地是“
?这不是一个吹毛求疵的/修辞性的问题——虽然我认为答案是肯定的,但我真的在问。难道语法->数据
涵盖的内容不是太多了吗?当然,您希望它只涵盖hello
,同时保持define
、print
和newline
的卫生性。是的,您当然都是对的。我会更新我的回复。谢谢,好多了。但请修正你的缩进-DI意味着原始的hello
具有定义它的语法上下文,这与它的用法不同。你的直觉是正确的。这并不像拼凑语法片段并对其进行评估那么简单。原因与支持局部推理有关。想象一下原始try.rkt
中的hello
的另一个定义。对(hello)
的呼叫应该指哪个?Racket架构师(以及其他人)认为,支持本地定义使程序更容易推理。你想要的行为是罕见的,因此需要更多的工作才能实现。