末尾呼出し最適化 - Scheme VM のお勉強

末尾呼出し最適化はコンパイル時に行われている。
末尾か?どうかの判定に tail? を定義。

(define (tail? next)
  (and (pair? next) (eq? (car next) 'return)))

next expression が return であれば末尾と判定する。分かりやすい。
理解のために実際に最適化 ON / OFF で何が違うのかを見比べてみる。

((lambda (a) ((lambda (b) 3))) 4)
=>
(frame () (constant 4 (argument (close (a) (close (b) (constant 3 (return)) (apply)) (apply)))))                   ;; 最適化 ON
(frame () (constant 4 (argument (close (a) (frame (return) (close (b) (constant 3 (return)) (apply))) (apply)))))  ;; 最適化 OFF

ぱっと見 frame / return が1つ減っていることが分かる。
なぜ減らしてもうまくいくのだろう?
分かったけど言語化が難しい。
ポイントは

  • 末尾なので「呼出し元の戻り値=今から呼び出す手続きの戻り値」であること
  • 手続き呼出しではなく、その場に body があるかのように実行できる
  • 「すかし」ができる

ということかな。

しかし VM になると物事がシンプルになるね。
楽しいし好きだ。