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

Rog*_*gon 4 macros language-extension racket

我现在已经坚持了几个小时的问题.我正在尝试使用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 ...   )]))
Run Code Online (Sandbox Code Playgroud)

现在我尝试在其他地方使用这种新语言:

try.rkt:

#lang s-exp "tinylang.rkt"
(hello)
Run Code Online (Sandbox Code Playgroud)

但是在加载第二个模块时,我收到错误"hello:模块中的未绑定标识符:hello".

stc*_*ang 5

问题是hello在词法范围内定义,tinylang.rkt但你希望它在范围内try.rkt.您可以使用datum->syntax设置一段语法的词汇上下文.

这将解决问题:

#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 ...   )]))
Run Code Online (Sandbox Code Playgroud)

更新:

在回应评论时,先前的解决方案可以简化为:

(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 ...   ))]))
Run Code Online (Sandbox Code Playgroud)

  • `syntax-> datum`不是太多了吗?当然,你希望它只覆盖`hello`,同时保持`define`,`print`和`newline`卫生. (3认同)