如果一个变量是用球拍语言定义的或者没有定义的话,你怎么会有不同的行为呢?
发布于 2013-11-20 04:01:17
有几种方法可以做到这一点。但我怀疑这些都不是您想要的,所以我只提供函数的指针(并解释每个函数的问题):
namespace-variable-value是从某个命名空间检索toplevel变量值的函数。不过,这只对REPL交互和REPL代码有用,因为模块中定义的代码无论如何都不会使用这些东西。换句话说,您可以使用这个函数(和相应的namespace-set-variable-value!)来获取值(如果有的话)并设置它们,但是这些值的唯一使用是在模块中本身并不存在的代码中。换句话说,使用这个工具就像保留一个将符号映射到值的哈希表一样好,只是在REPL上稍微方便一些,因为您只需键入名称.#%top宏。此宏将自动插入模块中未被绑定的所有名称。这个宏通常做的事情是抛出一个错误,但是您可以在代码中重新定义它(或者用您自己的语言重新定义它),用这些未知的名称来做其他事情。identifier-binding函数--再次,在宏中,而不是在运行时--并使用它获取有关宏的某个名称的信息,并根据该名称决定扩展到什么。最后两个选项更有用,但它们不是新手级的宏,这就是为什么我怀疑你问错了问题。为了澄清,您可以使用它们编写一种defined?特殊表单,它检查是否定义了某个名称,但这个问题将由宏根据其余代码回答,因此询问它并不真正有用。如果您希望能够在其他动态语言中启用使用此类谓词的代码,那么最好的方法是重新定义#%top,以执行某种查找(哈希表或全局命名空间),而不是抛出编译错误--但是,与显式使用哈希表之间的区别主要是修饰性的(再说一次,这不是一件新手的事情)。
发布于 2013-11-23 10:55:50
首先,读伊莱的答案。然后,根据Eli的答案,您可以这样实现defined?宏:
#lang racket
; The macro
(define-syntax (defined? stx)
(syntax-case stx ()
[(_ id)
(with-syntax ([v (identifier-binding #'id)])
#''v)]))
; Tests
(define x 3)
(if (defined? x) 'defined 'not-defined) ; -> defined
(let ([y 4])
(if (defined? y) 'defined 'not-defined)) ; -> defined
(if (defined? z) 'defined 'not-defined) ; -> not-defined它适用于这种基本情况,但它有一个问题:如果z未定义,则认为已定义并使用其值的if分支将引发编译时错误,因为普通if在运行时(动态)检查其条件值:
; This doesn't work because z in `(list z)' is undefined:
(if (defined? z) (list z) 'not-defined) 因此,您可能需要的是一个if-defined宏,它在编译时(而不是在运行时)告诉if的哪个分支:
#lang racket
; The macro
(define-syntax (if-defined stx)
(syntax-case stx ()
[(_ id iftrue iffalse)
(let ([where (identifier-binding #'id)])
(if where #'iftrue #'iffalse))]))
; Tests
(if-defined z (list z) 'not-defined) ; -> not-defined
(if-defined t (void) (define t 5))
t ; -> 5
(define x 3)
(if-defined x (void) (define x 6))
x ; -> 3https://stackoverflow.com/questions/20076868
复制相似问题