遅延評価に関連して

2年生用のscheme課題で、new-ifの問題が出ていた。

(define (new-if test then-exp else-exp)
(cond (test then-exp)
(else else-exp)))

(define (fac4 n)
(new-if (= n 0)
1
(* n (fac4 (- n 1)))))

これが無限ループになる理由を答えるものだが、逆に無限ループにならないようにするにはどうすればよいかだが、goshの構文のdelay forceを使うとこうなる。

(define (new-if test then-exp else-exp)
(cond (test (force then-exp))
      (else (force else-exp))))

(define (fac4 n)
(new-if (= n 0) 1
(delay (* n (fac4 (- n 1))))))

毎回delayを書くのが面倒だけども、Schemeにもdelayとforceがあるので、こういうことも出来るわけです。ただし、ポイントは上記ソースはgoshで動きますがguileでは動きません。guileでは、

(define (fac4 n)
(new-if (= n 0) (delay 1)
(delay (* n (fac4 (- n 1))))))

というようにしてやります。おそらくgoshの拡張の中でdelayに定数が渡っている場合にも動作するようになっているのでしょう。
下のソースのほうは、goshでもguileでも動きます。