如何在引用变量之前测试变量是否已定义?

时间:2010-07-16 17:20:15

标签: scheme

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

我喜欢有一个指定“调试级别”的全局。如果调试级别为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)

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

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

自引用'debug-level以来,可以对其进行评估并将其传递给eval。然后,当eval尝试评估它时,会发生错误,我希望guard能够捕获。它没有。

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

3 个答案:

答案 0 :(得分:4)

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

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

#;> (getprop 'cons (interaction-environment))
#<native procedure cons>
#;> (getprop 'x (interaction-environment))
#f
#;> (define x 100)
#;> (getprop 'x (interaction-environment))
100

但它只适用于顶层。

#;> (define (foo y)
  (let ((e (interaction-environment)))
    (display "Is X bound? ") (display (getprop 'x e))
    (newline)
    (display "Is Y bound? ") (display (getprop 'y e))
    (newline) ))
#;> (foo 1)
#;> Is X bound? 100
Is Y bound? #f

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

答案 1 :(得分:2)

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

(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)

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

答案 2 :(得分:1)

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

(defined? debug-level)

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

这种特殊形式不属于R5RS标准(除非我错过了,请double-check)。所以关于R5RS方案,除非你找到一个将其作为非标准扩展实现的方案,否则你运气不好。