たとえばこんなコード(変な数字が入ってるのはα変換後だから)
(define tarai (lambda (x.1 y.2 z.3) (if (not (< y.2 x.1)) y.2 (tarai (tarai (- x.1 1) y.2 z.3) (tarai (- y.2 1) z.3 x.1) (tarai (- z.3 1) x.1 y.2))))こいつをA正規形にするとこうなる
(define tarai (lambda (x.1 y.2 z.3) (let ((#:G267 (< y.2 x.1))) (let ((#:G268 (not #:G267))) (if #:G268 y.2 (let ((#:G269 (- x.1 1))) (let ((#:G270 (tarai #:G269 y.2 z.3))) (let ((#:G271 (- y.2 1))) (let ((#:G272 (tarai #:G271 z.3 x.1))) (let ((#:G273 (- z.3 1))) (let ((#:G274 (tarai #:G273 x.1 y.2))) (tarai #:G270 #:G272 #:G274)))))))))))見てのとおりコードが増大。それだけならまだいいのだが(よくないが)、問題はコードの増大に伴ってletが出現していること。
前回、継続周りで不具合が起きることを踏まえて、letが現れたらフレームを作るようにコンパイラとVMを修正したのだが、その影響で単なるたらいまわし関数がスタックオーバーフローを起こすようになった。
原因は、この大量のlet。これだけコードが増大すれば当然VMのインストラクションも増大する。どれだけ影響があるかスタックを1000から10000にして上記の関数でベンチマークをとってみた。
4秒が14秒に・・・orz
後の最適化がしやすいようにと思ってのA正規化だが、ちょっとないなぁ・・・
今のところこいつの恩恵って、変数の寿命がわかりやすいことだけだし・・・
どうしよう。
No comments:
Post a Comment