printf符号名称和值

时间:2013-03-10 15:50:07

标签: eval string-formatting racket

假设某处我定义了几个符号:

#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

2 个答案:

答案 0 :(得分:1)

首先,eval应该只用作Racket的最后手段。它使您的程序效率降低,难以理解。正确的方法是编写如下宏:

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

(define foo 2)
(f2 foo)

此宏只是将要查找的变量的名称替换为正文中的格式表达式。 quote将变量名称转换为可以打印的符号。此宏不适用于某个过程,因为(f2 foo)会在您foo之前推出quote并打印其名称。


注意:eval无法按预期工作的原因是因为eval始终根据命名空间进行评估,这决定了范围内的内容。模块中的默认命名空间中没有任何内容,因此eval无法看到foo或其他任何内容。您可以在Guide中了解有关命名空间的更多信息。

答案 1 :(得分:1)

另一个解决方案,也受到Asumu Takikawa的启发,使用了指南中描述的技巧:

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

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

与具有宏的解决方案形成对比,可以映射此函数。