【问题标题】:How to know whether a racket variable is defined or not如何知道是否定义了球拍变量
【发布时间】:2013-12-03 07:40:35
【问题描述】:

如果变量是用球拍语言定义的,或者没有用球拍语言定义,你怎么能有不同的行为?

【问题讨论】:

标签: variables racket defined


【解决方案1】:

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

  1. namespace-variable-value 是一个从某个命名空间检索顶级变量值的函数。不过,这仅对 REPL 交互和 REPL 代码有用,因为在模块中定义的代码无论如何都不会使用这些东西。换句话说,您可以使用这个函数(以及相应的namespace-set-variable-value!)来获取值(如果有的话)并设置它们,但是这些值的唯一用途是在模块本身不存在的代码中。换句话说,使用这个工具就像保留一个将符号映射到值的哈希表一样好,只是它在 REPL 中稍微方便一些,因为你只需键入名称......

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

  3. 一个稍微复杂一点的方法是使用identifier-binding 函数——同样,在一个中,而不是在运行时——并使用它来获取一些信息为宏指定的名称,并根据该名称决定要扩展的内容。

最后两个选项更有用,但它们不是新手级别的宏,这就是为什么我怀疑你问错了问题。澄清一下,您可以使用它们编写一种defined? 特殊形式来检查是否定义了某个名称,但该问题将由宏根据其余代码回答,所以不是问它真的很有用。如果您想要这样的东西可以在使用此类谓词的其他动态语言中启用那种代码,那么解决此问题的最佳方法是重新定义 #%top 以进行某种查找(哈希表或全局命名空间) 而不是抛出编译错误——但同样,这与显式使用哈希表之间的区别主要是装饰性的(同样,这不是新手)。

【讨论】:

  • 对于只在 REPL 中有效的东西,也可以简单地捕获 exn:fail:contract:variable? 异常。
  • 是的,但这不太适合新手使用,因为 (a) 您需要使用异常捕获代码包装每个顶级交互,一旦捕获它,就无法“跳回”到具有其他值的异常位置,因此您唯一能做的就是中止交互。
【解决方案2】:

首先,阅读 Eli 的回答。然后,根据 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 ; -> 3

【讨论】:

    猜你喜欢
    • 2013-09-03
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多