2013-03-10 53 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))) 

在与用宏该溶液中,该功能可以被映射。