2013-09-16 24 views
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 ... )])) 

現在,我嘗試在其他地方使用這個新的語言:

try.rkt:

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

但是,在加載s時出現錯誤「hello:模塊中的未綁定標識符爲:hello」第二個模塊。

+0

您也可以找到這個職位很有用。 http://stackoverflow.com/questions/2890493/how-do-i-define-functions-using-racket-macros – stchang

+0

謝謝@stchang,我看到那篇文章,它實際上幫助我開始這個項目。 – RogerTheDragon

回答

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

UPDATE:

在迴應評論,之前的解決方案可以簡化爲:

(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 ... ))])) 
+1

'(語法 - >數據#'____))'部分可以簡單地'____'嗎?不是一個挑剔的問題 - 雖然我認爲答案是肯定的,但我真的在問。 –

+3

'syntax-> datum'是否覆蓋太多?當然你希望它只覆蓋'hello',同時保持'define','print'和'newline'的衛生。 –

+1

是的,你當然都是正確的。我會更新我的迴應。謝謝。 – stchang