Как проверить, определена ли переменная, прежде чем ссылаться на нее? - PullRequest
6 голосов
/ 16 июля 2010

Я бы хотел иметь возможность проверить, определена ли переменная, прежде чем получить к ней доступ.

Мне нравится иметь глобальный объект, который определяет «уровень отладки». Если уровень отладки равен 0, дополнительные выходные данные не выдаются. Если значение больше 1, выводится отладочная информация с большей детализацией при больших числах.

Я также хотел бы настроить его так, чтобы процедуры запускались и принимали уровень 0, если я не удосужился его определить. Что-то вроде: (где defined? магия, которую я не знаю, как делать?

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

Я просмотрел сводку форм в Язык программирования схем, 4-е издание . Единственная возможность, которую я видел, была 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. Это не так.

EDIT 2 Я понял, что хочу обернуть отладочную трассировку в отдельную процедуру и что файл, который определяет эту процедуру, может также определить debug-level со значением по умолчанию 0. Причины использования Отдельная процедура состоит в том, чтобы уменьшить количество строк в процедурах, которые работают, а также разрешить перенаправление вывода отладочной информации, если это необходимо.

Ответы [ 3 ]

4 голосов
/ 17 июля 2010

Это полностью зависит от реализации, и похоже, что большинство реализаций не предоставляют ее удовлетворительно.

В схеме 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? и снова ВЗАИМОДЕЙСТВИЕ-ОКРУЖАЮЩАЯ СРЕДА.

2 голосов
/ 17 июля 2010

Неуклюжее, но работоспособное решение для R5RS. Используйте часто забываемую / забытую способность let-синтаксиса для переопределения ключевых слов. это неуклюже, потому что весь ваш файл упакован в синтаксис 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-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

1 голос
/ 16 июля 2010

Для резервного копирования проблема с функцией defined? состоит в том, что если вы напишите

(defined? debug-level)

Схема попытается оценить debug-level, что, конечно, является ошибкой, поскольку она не определена. Такая форма должна быть реализована внутренне компилятором / интерпретатором как особый случай.

Такая специальная форма не является частью стандарта R5RS (если я не пропустил ее, пожалуйста, перепроверьте ). Так что в отношении схем R5RS вам не повезло, если вы не найдете схему, которая реализует это как нестандартное расширение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...