SICP 4.1.7 Ex. 4.22 Ex. 4.23 Ex. 4.24

  • 投稿日:
  • カテゴリ:

構文解析

関数の構文解析を1度だけ実行し、内部形式にして保存する。PascalのP形式みたいなもの。関数の呼び出しは、内部形式のほうを呼ぶ。解析の手間が減って速くなる。
では、Schemeの関数の内部形式はどんな形をしているのか?どこに保存しているのか?残念ながら、この章ではこれらの具体的な説明はない。ここでは、子Schemeの内部形式は、親Schemeの内部形式をそのまま流用しているだけである。

Ex. 4.22

let の導入。(内部define の対応、名前つき let などの変更する前のシンプルな let)

まず analyze の変更

(define (analyze exp)
  (cond ((self-evaluating? exp) 
        ...
        ((if? exp)(analyze-if exp))
        ((let? exp)(analyze-let exp))  ;; let 節追加
        ...

追加した関数

(define (analyze-let exp)
  (let ((bindings (cadr exp))
        (body (cddr exp)))
    (analyze (cons (cons 'lambda 
                         (cons (map car bindings) body))
                   (map cadr bindings)))))

Ex. 4.23

並びが一つの式 exp1 の場合、Alyssa の analyze-sequence の返す値は以下のとおり。

(lambda (env) (execute-sequence exp1 env))

このうち、先頭の lambda と exp1 は構文解析済みになる。しかし、execute-sequence 関数の部分は構文解析されない。そのまま、lambda のなかに保存される。lambda の本体は解析されないからである。ということで未解析の部分式が残ってしまう。(解析と評価をごっちゃにしないこと。)

同じく、本文中の analyze-sequence の返す値は以下のとおり。

exp1

exp1 は構文解析済みである。

並びが2つの式 exp1, exp2 の場合、Alyssa の analyze-sequence の返す値は以下のとおり。

(lambda (env) (execute-sequence (exp1 exp2) env))

このうち、先頭の lambda と exp1 と exp2 は構文解析済みになる。が、execute-sequence 関数の部分が構文解析されないまま残り、lambda のなかに保存される。

同じく、本文中の analyze-sequence の返す値は以下のとおり。

(lambda (env) (exp1 env) (exp2 env))

exp1, exp2 と先頭の lambda は構文解析済みになる。式は、部分式も含めて、全て解析済みになる。

Ex. 4.24

1~n の和を求める関数を使って速度を比べる

(define (f n)
  (if (= n 1)
      1
      (+ (f (- n 1)) n)))

(f 1000000) の実行時間

内部形式使わない版 15秒

内部形式使う版 10秒

すこしだけ、内部形式を使うと速くなる