Рассмотрим этот негигиеничный макрос 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
, я использую символ там, где ожидается специальная форма или процедура ... Почему переводчик не остановился и не пожаловался на это?