4

我已经被一个问题困扰了好几个小时了。我正在尝试使用 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 ...   )]))

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

尝试.rkt:

#lang s-exp "tinylang.rkt"
(hello)

但是我在加载第二个模块时收到错误“你好:模块中的未绑定标识符:你好”。

4

1 回答 1

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 ...   )]))

更新:

作为对评论的回应,之前的解决方案可以简化为:

(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 ...   ))]))
于 2013-09-16T18:28:34.157 回答