Hello,
Consider this unhygienic Scheme macro:
(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)))))))))
It implements a for loop (I'm working with Gauche and Gambit):
> (for i 1 5 (print i)) 1 2 3 4 #
However, since I did not rename if
, this will certainly break:
(let ((if 'x))
(for i 1 5
(print i)))
It starts counting and never stops.
Now, I have tried macroexpanding this and couldn't see exactly why it loops instead of just signaling an error.
The expansion in Gambit (without the if
redefinition part) is this:
(let ((#:start15 1)
(#:stop16 5))
((letrec ((#:loop17 (lambda (i)
(if (< i #:stop16)
(begin (print i)
(#:loop17 (+ 1 i)))))))
#:loop17)
#:start15))))
And in Gauche:
(let ((:start4 1)
(:stop5 5))
(let :loop6 ((i :start4))
(if (< i :stop5)
(begin (print i)
(:loop6 (+ 1 i))))))
but if I'm inserting the symbol x
where the if
was, I'm using a symbol where a special form or procedure is expected... Why didn't the interpreter just stop and complain about that?