【问题标题】:How do I test whether a variable is defined before referencing it?如何在引用变量之前测试变量是否已定义?
【发布时间】:2010-07-16 17:20:15
【问题描述】:

我希望能够在访问变量之前测试它是否已定义。

我喜欢有一个指定“调试级别”的全局变量。如果调试级别为 0,则不提供额外输出。当大于 1 时,给出调试输出,数字越大越详细。

如果我还没有开始定义它,我还想设置它以便程序运行,并假设级别 0。类似于:(defined? 是我不知道该怎么做的魔法?

(if (and (defined? debug-level) (> debug-level 1))
    (diplay "Some debugging info"))

我查看了The Scheme Programming Language, 4th Edition 中的表格摘要。我认为唯一有可能的是identifier?。它没有用。

我正在使用 SISC 1.16.6(声称符合 R5RS)和 Chez Petite Scheme v8(声称符合 R6RS)

编辑我尝试用guard 包装eval,例如:

(guard (x (else #f)) (eval 'debug-level))

由于引用了'debug-level,它可以被评估并传递给eval。然后当eval 尝试评估它时,会发生一个错误,我希望guard 能抓住它。它没有。

EDIT 2 我意识到我想将调试跟踪包装到一个单独的过程中,并且定义该过程的文件也可以定义debug-level,默认值为0。使用的原因一个单独的过程是为了减少过程中有效的行数,并在需要时允许调试输出的重定向。

【问题讨论】:

    标签: scheme


    【解决方案1】:

    这完全取决于提供的实现,而且看起来大多数实现都不能令人满意地提供它。

    在 SISC 方案中,看起来你可以使用 GETPROP 来达到这个效果,但是环境不会自动更新哦,看,你可以使用这个叫做 INTERACTION-ENVIRONMENT 的东西:

    #;> (getprop 'cons (交互环境)) # #;> (getprop 'x (交互环境)) #F #;> (定义 x 100) #;> (getprop 'x (交互环境)) 100

    但它只适用于顶层。

    #;> (定义 (foo y) (让((e(交互环境))) (display "Is X bound?") (display (getprop 'x e)) (新队) (display "Is Y bound?") (display (getprop 'y e)) (新队) )) #;> (foo 1) #;> X 是绑定的吗? 100 Y 有界吗? #F

    对于 Chez,您又拥有 TOP-LEVEL-BOUND? 和 INTERACTION-ENVIRONMENT。

    【讨论】:

    • 谢谢。我担心答案不会被广泛移植,它要么是 R6RS 中的新东西,要么是特定于实现的。 +1,但我会让这个答案过时一点,看看是否有更好的想法在接受正确之前发布。
    【解决方案2】:

    用于 R5RS 的笨重但可行的解决方案。使用 let-syntax 经常被忽视/遗忘的能力来重新定义关键字。这很笨拙,因为您的整个文件都包含在 let 语法中,并且因为它为每个定义增加了一些开销。我使用关联列表来记住定义,哈希表会是更好的选择。

    (define define-list '())
    (define define-list-add 
      (lambda (key value)
        (set! define-list (cons `(,key ,value) define-list))))
    
    (let-syntax (
                 (define (syntax-rules ()
                           ((_ (pro-name args ...) body ...) 
                            (begin
                              (define (pro-name args ...) body ...)
                              (define-list-add pro-name  '((pro-name args ...) body ...))))
                           ((_ pro-name pro) (begin
                                               (define pro-name pro)
                                               (define-list-add 'pro-name 'pro)))
    
                           ))
                 (defined?
                   (syntax-rules ()
                     ((_ sym) (begin (if (assoc (quote sym) define-list) #t #f)))))
                 )
      (define y (lambda () x))
    
      (display (defined? y))
      (newline)
      (display (defined? x))
      )
    

    打印

    #t
    #f
    

    在球拍下面:一个模块用于重新定义define,将每个符号和定义存储在一个名为define-list的列表中。宏定义?查看此列表以查看天气是否已定义。

    (module qdefine mzscheme
      (provide ;(all-from-except mzscheme let)
       (rename define olddefine)
       (rename quote-define define)
       defined?)
    
      (define define-list '())
      (define define-list-add 
        (lambda (key value)
          (set! define-list (cons `(,key ,value) define-list))))
    
      (define-syntax quote-define
        (syntax-rules ()
          ((_ (pro-name args ...) body ...) 
           (begin
             (define (pro-name args ...) body ...)
             (define-list-add pro-name  '((pro-name args ...) body ...))))
          ((_ pro-name pro) (begin
                              (define pro-name pro)
                              (define-list-add 'pro-name 'pro)))
    
          ))
    
      (define-syntax defined?
        (syntax-rules ()
          ((_ sym) (begin (if (assoc (quote sym) define-list) #t #f)))))
      )
    (require 'qdefine)
    
    (define y (lambda () x))
    
    (defined? y)
    (defined? x)
    

    在 guile 中它只是被定义?显然: http://www.delorie.com/gnu/docs/guile/guile_289.html

    【讨论】:

    • Racket 确实有反射工具来做这样的事情,但这样的事情(包括 interaction-environment,无论 Guile 做什么等)总是不稳定的解决方案,会以某种方式受到影响。
    【解决方案3】:

    备份一下,defined? 函数的问题是,如果你写

    (defined? debug-level)
    

    方案将尝试评估debug-level,这当然是一个错误,因为它没有定义。作为特殊情况,这种形式必须由编译器/解释器在内部实现。

    这样的特殊形式不是 R5RS 标准的一部分(除非我错过了,请double-check)。因此,对于 R5RS 方案,除非您找到将其实现为非标准扩展的方案,否则您将不走运。

    【讨论】:

    • 我不是要函数defined?,因为正如你所说,函数不起作用。但是一个函数也不适用于if,但方案有if。在其他工作中,寻找一种特殊的形式,或其他方式来达到结果。 (可能是宏?)
    • 当然。我想说的是,这必须是该语言提供的内置形式之一,例如if,而规范(至少是 R5RS)似乎不包括这种形式。
    猜你喜欢
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    • 2016-05-28
    • 1970-01-01
    相关资源
    最近更新 更多