8

私はSICPの次のセクションを読んでいます

http://mitpress.mit.edu/sicp/full-text/book/book-ZH-26.html#%_sec_4.1.7

テキストによると、eval何度も評価される式は 1 回しか分析されないため、次の will better の変換によりパフォーマンスが向上します。

(define (eval exp env)
    ((analyze exp) env))

これは本で与えられたanalyze関数です:

(define (analyze-if exp)
(let ((pproc (analyze (if-predicate exp)))
    (cproc (analyze (if-consequent exp)))
        (aproc (analyze (if-alternative exp))))
    (lambda (env)
        (if (true? (pproc env))
            (cproc env)
                (aproc env)))))

analyze本が一度だけ実行されると言っている理由がわかりません。基本的に毎回呼び出されると言うの本体はevalパラメータとして呼び出されるのではないでしょうか?これは、が呼び出されるたびに が呼び出されることを意味します。((analyze exp) env))evalanalyzeexpanalyzeeval

私の理解の何が問題になっていますか?フィードバックをいただければ幸いです。

4

3 に答える 3

5

eval実際、プログラム コードをパラメーターとして呼び出すたびに、構文エバリュエーターが呼び出されます。ただし、そのコード内の関数がそのコード内の別の関数を呼び出す場合 (または、最も単純なケースでは、再帰によって自分自身を呼び出す場合)、インナーapplyは分析された式 (最終的にはラムダ関数) を引数として取得します。実行するために再度構文解析する必要があるコードの塊ではありません。

于 2010-10-13T21:22:22.133 に答える
5

ギンタウタスの答えは正しいですが、例が適切かもしれません。ループ構造を備えた Scheme 方言を開発したとします。

(do-n-times n expr)

明白なセマンティクスで。evalここで、 10 回実行されるループを評価するためにナイーブを呼び出すと、

(eval '(do-n-times 10 (print 'hello)))

次に、ループ本体を 10 回分析します。eval分析と評価を分離する のバージョンでは、ループ本体はanalyze1 回 d され、その後 10 回評価されます。

分析フェーズは、Scheme インタープリターで高速である場合とそうでない場合があるプロシージャを返します。ただし、あらゆる種類の最適化 (デッド コード分析、マシン コードへのJIT コンパイルなど) を実行できる可能性があります。

于 2010-10-15T15:12:59.140 に答える
2

larsmans の回答は非常に優れています。

補足的な回答として、事前にパラメーターが渡された場所のanalyze(environ)カリー化された形式として表示することもできます。SICP では、次のようなサンプル コードを読むことができます。eval(expr, environ)expr

(define (analyze-assignment exp)
  (let ((var (assignment-variable exp))
        (vproc (analyze (assignment-value exp))))
    (lambda (env)
      (set-variable-value! var (vproc env) env)
      'ok)))

が渡されたlet (([var] [preprocessed stuff]))ときに必要になるまで、前処理がクロージャーに格納されていることがわかります。environ

于 2011-11-06T11:45:09.933 に答える