2013-03-10 51 views
1

假設某處我已經定義了幾個符號:printf的符號名和值

#lang racket 
(define foo 123) 
(define bar '("1" "2" "3")) 

我需要一種方法來產生像"foo = 123""bar = '("1" "2" "3")"的字符串。我寫了一個函數:

(define (f2 sy) 
    (format "~a = ~s" sy (eval sy))) 

這個函數在解釋器窗口工作得很好。

> (f2 'foo) 
"foo = 123" 
> (f2 'bar) 
"bar = (\"1\" \"2\" \"3\")" 

這對我來說非常滿意。然而,當我在代碼中使用它時,我得到了

foo: unbound identifier; 
also, no #%top syntax transformer is bound in: foo 

我有一種感覺,我做錯了什麼。你能否建議正確的方法來解決我的問題?

P.S:我使用DrRacket, version 5.3.1

+0

Asumu Takikawa提出了兩種解決方案:寫一個宏,但不能在列表中映射,或者引用某個命名空間,如下所示: – skobls 2013-03-10 19:27:46

回答

1

首先,eval真的應該只被用作拍最後的手段。它會使你的程序效率降低,難以理解。這樣做的正確的方式可能是編寫一個宏,如以下幾點:

(define-syntax-rule (f2 sy) 
    (format "~a = ~s" (quote sy) sy)) 

(define foo 2) 
(f2 foo) 

這個宏只是代替你想查找到體內的形式表達變量的名稱。 quote將變量名稱變成可以打印的符號。這個宏不能作爲一個程序工作,因爲(f2 foo)會在quote之前遵循foo並打印它的名字。


注:爲什麼按預期eval不工作的原因是因爲eval總是相對於一個命名空間,這就決定什麼範圍評估。模塊中的默認名稱空間沒有任何內容,因此eval看不到foo或其他任何內容。您可以在Guide中閱讀關於命名空間的更多信息。

+0

感謝您的答覆。但是有可能把這個宏映射到一個符號列表?在我的問題中,我需要多次調用我的'f2'。 – skobls 2013-03-10 17:09:15

+0

不,你不能'映射'一個宏,因爲它不是一個過程。你可以編寫一個可以同時在多個標識符上工作的'f2'版本。 – 2013-03-10 17:35:11

+0

你能否提供一些提示或參考資料如何做到這一點? – skobls 2013-03-10 19:21:04

1

另一種解決方案,還通過Asumu滝川啓發使用指南中描述的特技:

(define-namespace-anchor a) 
(define ns (namespace-anchor->namespace a)) 

(define (f2 sy) 
    (format "~a = ~s" sy (eval sy ns))) 

在與用宏該溶液中,該功能可以被映射。