假设某处我定义了几个符号:
#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 :(得分: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)))
与具有宏的解决方案形成对比,可以映射此函数。