Macros 使用Racket进行语言扩展,通过宏定义辅助函数

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)

我已经被一个问题困扰了好几个小时了。我正在尝试使用Racket的语言扩展功能定义DSL。我想做一些类似以下伪代码的事情。最终,我想在DSL中生成函数和宏,这些函数和宏中的大部分现在似乎都可以工作了,问题在于提供的定义应该与声明在同一级别上工作。这可能吗?时间不早了,我肯定我错过了一些非常琐碎的事情。这个问题最基本的例子是:

tinylang.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)
现在我尝试在其他地方使用这种新语言:

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架构师(以及其他人)认为,支持本地定义使程序更容易推理。你想要的行为是罕见的,因此需要更多的工作才能实现。