Exercise 4.9

while の展開を行う処理を考えてみる。 束縛変数のない名前付き let でループさせれば等価になるはずなので、

(define (while-predicate exp) (cadr exp))
(define (while-body exp) (cddr exp))
(define (while->let exp)
  (let->combination
    (make-named-let 'while
                    '()
                    (list (make-if (while-predicate exp)
                             (make-begin (append (while-body exp) '((while))))
                             '#t )))))

としてみた。while の値が #t になっているけど、ここは別に何でもいいと思う。ちなみにGauche は while の値は不定みたいだ。

実際に展開させてみると、

gosh> (while-expand '(while (< i 10) (set! i (+ i 1)) (print i)))
((lambda ()
   (define while
     (lambda () (if (< i 10)
                  (begin (set! i (+ i 1))
                         (print i)
                         (while))
                  #t)))
   (while)))

となる。手続きの名前に while を使ってるけど、定義した後で即座に呼び出しているので評価時に実は別のモノに束縛されてました、みたいなことにはならないはず。

gosh> (define i 0)
i
gosh> (eval (while-expand '(while (< i 10) (set! i (+ i 1)) (print i))) '())
1
2
3
4
5
6
7
8
9
10
#t

うまくいった。ただ、実際には名前付き let を let に展開した時のように while の body の部分も逐次展開していく必要がある。