Механика захвата переменных с define-macro в Scheme - PullRequest
2 голосов
/ 09 октября 2010

Рассмотрим этот негигиеничный макрос Scheme:

(define-macro for
  (lambda (i i1 i2 . body)
    (let ((start (gensym))
          (stop  (gensym))
          (loop  (gensym)))
      `(let ((,start ,i1)
             (,stop  ,i2))
         (let ,loop ((,i ,start))
              (if (< ,i ,stop)
                  (begin ,@body
                         (,loop (+ 1 ,i)))))))))

Он реализует цикл for (я работаю с Gauche и Gambit):

> (for i 1 5
       (print i))
1
2
3
4
#

Однако, поскольку я не переименовалif, это непременно сломается:

(let ((if 'x))
  (for i 1 5
       (print i)))

Он начинает отсчет и никогда не останавливается.

Теперь я попытался макроэкспандировать это и не смог точно понять, почему он зацикливается, а не простосигнализируя об ошибке.

Расширение в Gambit (без переопределенной части if) выглядит так:

(let ((#:start15 1)
      (#:stop16 5))
 ((letrec ((#:loop17 (lambda (i) 
                       (if (< i #:stop16) 
                           (begin (print i)
                                  (#:loop17 (+ 1 i))))))) 
     #:loop17)
   #:start15))))

И в Gauche:

(let ((:start4 1)
      (:stop5 5))
  (let :loop6 ((i :start4))
       (if (< i :stop5)
           (begin (print i)
                  (:loop6 (+ 1 i))))))

, но еслиЯ вставляю символ x там, где был if, я использую символ там, где ожидается специальная форма или процедура ... Почему переводчик не остановился и не пожаловался на это?

1 Ответ

5 голосов
/ 09 октября 2010

Вы связываете if как простое значение, что означает, что (if blah blah blah) больше не является специальной формой, а это означает, что оно превращается в приложение-функцию. Это приложение, очевидно, приведет к ошибке, но поскольку схема является строгой, вам необходимо оценить аргументы этой функции, прежде чем пытаться ее применить. (Это может прекратиться с ошибкой, как только выражение функции оценивается как не-функция, но реализации редко делают это.) Поэтому сначала выполняется рекурсивный вызов цикла, но это приводит к другому if вызову функции и т. Д.

Но что более важно:

define-macro вредно для вашего здоровья

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