2011-04-01 46 views
4

我想寫一個define的包裝,它存儲傳遞給它的值。我一直以嬰兒的方式接近它(一般來說對Lisp來說是新手,對於Scheme來說更新),但卻遇到了困難。套!全球從計劃宏嗎?

球拍,我開始有:

> (require (lib "defmacro.ss")) 
> (define-macro (mydefine thing definition) 
     `(define ,thing ,definition)) 
> (mydefine a 9) 
> a 
9 

好吧,這工作。時間做一些宏,返回S-exprs之前:

> (define-macro (mydefine thing definition) 
    (display "This works") 
    `(define ,thing ,definition)) 
> (mydefine a "bob") 
This works 
> a 
"bob" 

尼斯。但我不能爲我的生命得到它的設置,而不是顯示一些全局變量:

> (define *myglobal* null) 
> (define-macro (mydefine thing definition) 
    (set! *myglobal* "This does not") 
    `(define ,thing ,definition)) 
> (mydefine a ":-(") 
set!: cannot set identifier before its definition: *myglobal* 

如何做到這一點的任何建議,將不勝感激。

我懷疑我正試圖在這裏游泳,或者通過擺脫Scheme中宏的全局變量,或者使用define-macro而不是學習宏創建的Scheme特定語法。

回答

6

您正在運行對球拍的相分離 - 這意味着每個階段(運行時間和編譯時間)在不同的世界中運行。正如Vijay所指出的,解決這個問題的一種方法是在運行時做你想做的事情,但這可能不是你長期需要的。問題在於,嘗試這些事情通常意味着您將希望在編譯時級別存儲一些語法信息。例如,假設您想要存儲所有已定義名稱的名稱,以便在第二個宏中使用它們將全部打印出來。你會做如下(我在這裏用理智宏,define-macro是不應該被用於實際工作中遺留的黑客,你可以在guide看這些東西,然後在reference):

#lang racket 
(define-for-syntax defined-names '()) 
(define-syntax (mydefine stx) 
    (syntax-case stx() 
    [(_ name value) 
    (identifier? #'name) 
    (begin (set! defined-names (cons #'name defined-names)) 
      #'(define name value))] 
    ;; provide the same syntactic sugar that `define' does 
    [(_ (name . args) . body) 
    #'(mydefine name (lambda args . body))])) 

請注意,defined-names是在語法級別定義的,這意味着正常運行時代碼無法引用它。實際上,您可以在運行時級別綁定不同的值,因爲兩個綁定是不同的。現在完成了,您可以編寫使用它的宏 - 儘管在運行時無法訪問defined-names,但它在語法級別是一個普通綁定,因此:

(define-syntax (show-definitions stx) 
    (syntax-case stx() 
    [(_) (with-syntax ([(name ...) (reverse defined-names)]) 
      #'(begin (printf "The global values are:\n") 
        (for ([sym (in-list '(name ...))] 
          [val (in-list (list name ...))]) 
         (printf " ~s = ~s\n" sym val))))])) 
4

該聲明(set! *myglobal* "This does not")變壓器環境執行,不是正常的環境。所以它無法找到*myglobal。我們需要在定義了*myglobal*的環境中同時執行兩個表達式。

這裏是一個解決方案:

(define *defined-values* null) 

(define-macro (mydefine thing definition) 
    `(begin 
    (set! *defined-values* (cons ,definition *defined-values*)) 
    (define ,thing ,`(car *defined-values*)))) 


> (mydefine a 10) 
> (mydefine b (+ 20 30)) 
> a 
10 
> b 
50 
> *defined-values* 
(50 10) 
> (define i 10) 
> (mydefine a (begin (set! i (add1 i)) i)) ;; makes sure that `definition` 
              ;; is not evaluated twice. 
> a 
11 

如果該計劃實現不提供define-macrodefine-syntaxmydefine可以定義爲:

(define-syntax mydefine 
    (syntax-rules() 
    ((_ thing definition) 
    (begin  
     (set! *defined-values* (cons definition *defined-values*)) 
     (define thing (car *defined-values*))))))