Variables 如何知道球拍变量是否已定义

Variables 如何知道球拍变量是否已定义,variables,racket,defined,Variables,Racket,Defined,如果在racket语言中定义了变量或没有定义变量,您如何能有不同的行为?有几种方法可以做到这一点。但我怀疑这些都不是您想要的,因此我只提供指向函数的指针(并解释每个函数的问题): 是一个从某个命名空间检索顶级变量值的函数。不过,这仅对REPL交互和REPL代码有用,因为模块中定义的代码无论如何都不会使用这些东西。换句话说,您可以使用此函数(以及相应的名称空间设置变量值!)获取值(如果有)并进行设置,但这些值的唯一用途是在模块中本身不存在的代码中。换言之,使用此功能就像保留一个将符号映射到值的哈希

如果在racket语言中定义了变量或没有定义变量,您如何能有不同的行为?

有几种方法可以做到这一点。但我怀疑这些都不是您想要的,因此我只提供指向函数的指针(并解释每个函数的问题):

  • 是一个从某个命名空间检索顶级变量值的函数。不过,这仅对REPL交互和REPL代码有用,因为模块中定义的代码无论如何都不会使用这些东西。换句话说,您可以使用此函数(以及相应的
    名称空间设置变量值!
    )获取值(如果有)并进行设置,但这些值的唯一用途是在模块中本身不存在的代码中。换言之,使用此功能就像保留一个将符号映射到值的哈希表一样,只是在REPL上更方便一些,因为您只需键入名称

  • 更有可能的是,这些事情是在宏中完成的。第一种方法是使用特殊的宏。对于模块中未知绑定的所有名称,将自动插入此宏。这个宏通常会抛出一个错误,但是您可以在代码中重新定义它(或者用自己的语言重新定义它),用这些未知的名称执行其他操作

  • 一种稍微复杂一点的方法是使用函数——同样,在宏中,而不是在运行时——并使用它获取有关给定给宏的某个名称的信息,并根据该名称决定扩展到什么


  • 最后两个选项更有用,但它们不是新手级别的宏,这就是为什么我怀疑你问错了问题。为了澄清,您可以使用它们编写一种
    defined?
    特殊表单,检查是否定义了某个名称,但这个问题将由宏根据代码的其余部分来回答,因此询问它并不是真正有用的。如果您想在其他动态语言中使用类似谓词的代码类型,那么最好的方法是重新定义
    #%top
    以进行某种查找(哈希表或全局命名空间),而不是抛出编译错误,这与显式使用哈希表的区别主要是表面上的(同样,这不是一件新手的事情)。

    首先,阅读Eli的答案。然后,根据Eli的回答,您可以通过以下方式实现
    定义的?
    宏:

    #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
    在运行时(动态)检查其条件值:

    所以,您可能需要一个
    if定义的
    宏,它在编译时(而不是在运行时)告诉
    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 ; -> 3
    

    你到底是什么意思?您是否试图在某个地方使用未定义的变量?我无法回答您的问题。请看。对于只在REPL中工作的东西,您也可以简单地捕获
    exn:fail:contract:variable?
    异常。是的,但这不太适合新手使用,因为(a)您需要用异常捕获代码包装每个顶级交互,一旦捕获,就无法“跳回”将异常位置与其他值绑定,因此您唯一能做的就是中止交互。
    #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 ; -> 3