How do I test whether a variable is defined before referencing it?

前端 未结 3 1170
庸人自扰
庸人自扰 2021-02-09 15:04

I would like to be able to test whether a variable is defined, prior to accessing it.

I like to have a global that specifies a \"debug level\". If debug level is 0, no

相关标签:
3条回答
  • 2021-02-09 15:16

    This is totally up to the implementation to provide, and it looks like most implementations don't satisfactorily provide it.

    In SISC scheme, it looks like you can use GETPROP to this effect, but environments don't update automatically oh, look, there's this thing called INTERACTION-ENVIRONMENT that you can use:

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

    But it only works on the top level.

    #;> (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
    

    For Chez you have TOP-LEVEL-BOUND? and INTERACTION-ENVIRONMENT again.

    0 讨论(0)
  • 2021-02-09 15:24

    To back up a bit, the problem with a defined? function is that if you write

    (defined? debug-level)
    

    Scheme will attempt to evaluate debug-level, which of course is an error since it is not defined. Such a form would have to be implemented internally by the compiler/interpreter as a special case.

    Such a special form is not part of the R5RS standard (unless I missed it, please double-check). So with regard to R5RS schemes you are out of luck unless you find a Scheme that implements this as a non-standard extension.

    0 讨论(0)
  • 2021-02-09 15:36

    Clunky but workable solution for R5RS. Use the often neglect/forgotten ability of let-syntax to redefine keywords. this is clunky because your whole file is wrapped in a let-syntax and because it adds some overhead to each define. I use a associative list to remember definitions, a hash table would be a beter choice.

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

    prints

    #t
    #f
    

    Below in racket: a module is used to redefine define to store each symbol and definition in a list called define-list. The macro defined? looks in this list to see if weather or not the symbol has been defined.

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

    In guile it is just defined? apparently: http://www.delorie.com/gnu/docs/guile/guile_289.html

    0 讨论(0)
提交回复
热议问题