3

Harold Abelson と Gerald Jay Sussman による有名な本「Structure and Interpretation of Computer Programs」に従って、Scheme に Metacircular Evaluator を実装しようとしています。

http://mitpress.mit.edu/sicp/full-text/sicp/book/node79.htmlhttp://mitpress.mit.edu/sicp/full-text/sicp/book/node80.html

著者は、次の方法で環境をセットアップすることを提案しています。

(define (define-variable! var val env)
  (let ((frame (first-frame env)))
    (define (scan vars vals)
      (cond ((null? vars)
             (add-binding-to-frame! var val frame))
            ((eq? var (car vars))
             (set-car! vals val))
            (else (scan (cdr vars) (cdr vals)))))
    (scan (frame-variables frame)
          (frame-values frame))))

(define (setup-environment)
  (let ((initial-env
         (extend-environment (primitive-procedure-names)
                             (primitive-procedure-objects)
                             the-empty-environment)))
    (define-variable! 'true true initial-env)
    (define-variable! 'false false initial-env)
    initial-env))

ただし、理由がわかりません

(define myenv (setup-environment))

私が知っているように、Scheme はデフォルトで値によって関数に変数を渡すため、Scheme で期待どおりに動作するはずです。initial-env に変更すると、initial-env は毎回変更されず、setup-environment 関数は、extend-environment が返した値を返します。

私の理解のどこが間違っていますか、教えていただけますか?

前もって感謝します!

4

2 に答える 2

5

あなたの質問はもう少し具体的かもしれませんが私はそれを理解していると思います。

具体的には、あなたの質問は次のように思われます。

「私はの行動に驚いています

(define myenv (setup-environment))
(define-variable! 'a 13 myenv)
(lookup myenv 'a)

具体的には、Schemeは値による呼び出しであるため、失敗すると予想されます。」これはあなたの質問ですか?

もしそうなら、私はそれに答えることができると思います。値による呼び出しは、値が変更できないことを意味するものではありません。これは、関数呼び出しが呼び出し元から呼び出し先に値を渡すことを含むことを意味します。実際、ほぼすべての言語は値による呼び出しです。この用語は広く誤解されています。たとえば、Javaは値による呼び出し言語でもあります。

したがって、Schemeについては、値を変更または「変更」することを妨げるものは何もありません。この例では、set-car!呼び出しは参照しているリストを変更します。この変更は、この値を「見る」ことができるすべてのコードに表示されます。

あなたの根本的な質問は、「価値による呼びかけ」が何を意味するのかということと本当に関係があると思います。そして、私がそれに光を当てたことを願っています。

于 2012-03-16T17:59:55.893 に答える
2

これがどのように機能するかを理解するには、まず変数が環境の最初のフレームinitial-envを指し、この参照が変更されないことを理解する必要があります。環境自体はフレームのリストであり、各フレームはリストのペアであり、最初のフレームの は変数のリストの先頭であり、最初のフレームの は値のリストの先頭です。carcdr

scanそれが明確になったら、手順とadd-binding-to-frame!作業方法を認識する必要があります。Scan現在のフレーム内の変数のリストで、と同じ名前の変数を探しますvar。見つかった場合は、値のリスト内の対応する値を置き換えます。変数が見つからない場合、add-binding-to-frame!新しい変数と新しい値を対応するリストの先頭に追加し、フレームを更新してこの新しい先頭を指すようにします。initial-environmentがまだ最初のフレームを指していて、最初のフレームがまだ変数と値のリストの先頭を指していることに注意してください(ただし、新しいバインディングがあります)。

ご覧のとおり、initial-env変更されていませんが、そこに含まれるリストはその場で変更されたため、それぞれの値を持つ新しい変数が追加されています。プロセス全体を理解する最善の方法は、ペンと紙を手に取り、関係するコンス セルを変更した結果を段階的に描くことだと思います。

于 2012-03-16T22:32:46.593 に答える