5

したがって、Scheme では define が動的スコープ用であり、let が静的スコープ用であることを知っていますが、次のことは私を混乱させます。

私が持っている場合

(let ((x 0))
  (define f (lambda () x))
  (display (f))
  (let ((x 1))
    (display (f))
    )
  )

00 が表示されます。ただし、次のように x の定義を追加すると、次のようになります。

(let ((x 0))
  (define f (lambda () x))
  (display (f))
  (define x 4)
  (let ((x 1))
    (display (f))
    )
  )

undefined4 と表示されます。どうしてこれなの?f を評価した後にx を定義すると (f) の戻り値に影響するのはなぜですか? そして、戻り値が「未定義」なのはなぜですか?

また、define の代わりに letrec を使用して f をバインドしても機能することにも言及する価値があります。

(let ((x 0))
  (letrec ((f (lambda () x)))
  (display (f))
  (define x 4)
  (let ((x 1))
    (display (f))
    )
  )
)

00 を返します。

注: DrRacket の言語を「Pretty Big」に設定して使用しました。

4

3 に答える 3

5

2 番目のケースで発生している問題は、変数が定義されているスコープ全体に対して変数を(define x 42)作成することです。現在、変数はスコープ全体に対して定義されていますが、そのは実際の行まで未定義です。x(define x 42)

(let ()
  ;; up here, `x` is defined but has an undefined value
  ;; ...
  (define x 42)
  ;; down here `x` has the value 42
  ;; ...
  )

次のように動作しています。

(let ([x 'undefined])
  ;; ... up here, `x` is 'undefined
  (set! x 42)
  ;; ... down here, `x` is 42
  )
于 2013-02-19T02:00:14.660 に答える
1

2番目と3番目のコードスニペットはSchemeではありません(R5RS、R6RS、R7RSのいずれでもありません)。(<body>およびletその他の)は次のように定義されます。

<body> -> <definition>* <sequence>
<sequence> -> <command>* <expression>
<command> -> <expression>

したがって、define(は<definition>)をフォローすることはできませんdisplay<expression>)。コンパイラ/インタプリタが「let」の展開を誤って処理しているため、混乱を招く結果が生じる可能性があります。

「優れた」R6RSコンパイラの機能は次のとおりです。

> (let ((x 0))
  (letrec ((f (lambda () x)))
  (display (f))
  (define x 4)
  (let ((x 1))
    (display (f))
    )
  )
)
Unhandled exception
 Condition components:
   1. &who: define
   2. &message: "a definition was found where an expression was expected"
   3. &syntax:
       form: (define x 4)
       subform: #f
   4. &trace: #<syntax (define x 4)>
> 
于 2013-02-25T04:18:28.363 に答える
0

ケース 1: f の本体は両方の呼び出しで最も外側の let にバインドされ、静的スコープが要求する 00 になります。

ケース 2: これについてはよくわかりませんが、内部(define x 4)は最も外側の x=0 バインディングをシャドウし、テキスト上では f の呼び出しの後であるにもかかわらず、スコープ内にあります。次に、評価のトリッキーな順序により、新しい x バインディングが完全に初期化される前に最初の呼び出しが発生するため、「初期化されていません」。内部 let の 2 番目の呼び出しは、すべてが初期化された後に発生するため、4.

ケース 3: letrec と define を別々のスコープに明示的に配置したので、f は明らかに最も外側の let を参照します。define はここでは何もしません。

于 2013-02-19T01:41:33.767 に答える