letrec の実装 - Scheme VM を書く

letrec は教科書的には

(letrec ([a (lambda () ...)])
   (a))

=>

(let ([a (if #f #f)])
  (set! a (lambda (() ...)))
  (a))

という式に変換できる。((if #f #f) は undef の取り出しです。)
いままでは letrec の実装はまさにコンパイル前にこの変換をかけていました。


この方法は1つ大きな問題があって「letrec である」という情報が失われてしまい後続の処理で letrec の最適化ができないことに気づきました。
例えば典型的な internal define における自己末尾再帰の最適化を jump にするなんてのが非常にやりづらい。
なので中間表現において let と letrec を判別してコンパイル時に上の変換と同等のコードを吐くように変換しました。