(defun interp (x &optional env) (prog nil :loop (cond ((symbolp x) (return (get-var x env))) ((atom x) (return x)) ((scheme-macro (car x)) (setf x (scheme-macro-expand x)) (go :loop)) ((member (car x) '(quote set! lambda)) (return (interp-specialform (car x) (cdr x) env))) ((eq (car x) 'begin) (setq x (cdr x)) (do ((l x (cdr l))) ((null (cdr l)) (setq x (car l))) (interp (car l) env)) (go :loop)) ((eq (car x) 'if) (setq x (cdr x)) (setq x (if (interp (car x) env) (cadr x) (caddr x))) (go :loop)) (t (let ((proc (interp (car x) env)) (args (mapcar #'(lambda (v) (interp v env)) (cdr x)))) (if (closure-p proc) (progn (setq x (closure-code proc)) (setq env (extend-env (closure-params proc) args (closure-env proc))) (go :loop)) (return (apply proc args))))))))そこで,前に定義していたinterpとの処理時間の差を調べてみます. 時間を調べるためにはScheme-interpreterに時間を 調べる手続きを組み込むという方法も可能ですが, 処理時間をはかるためのベンチマーク用に使えるfib関数の定義とその実行形 式を与えてbeginで複合文かしたものをinterp手続きに渡し, それをLispのtime手続きに渡すという手法を使ってみます. 繰り返し処理をしない前のinterpでは,
<cl> (time (interp '(begin (define (fib n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))) (fib 12)))) cpu time (non-gc) 21900 msec user, 1049 msec system cpu time (gc) 2716 msec user, 34 msec system cpu time (total) 24616 msec user, 1083 msec system real time 27210 msec 233となります. 繰り返し処理に変更すると,
cpu time (non-gc) 21283 msec user, 783 msec system cpu time (gc) 583 msec user, 17 msec system cpu time (total) 21866 msec user, 800 msec system real time 23520 msecとなりました. これよりいくらか効果があることがわかります.