31

私は、静的スコープが物事を行うための唯一の正しい方法であり、動的スコープが悪魔のツールであり、インタープリター/コンパイラーの不十分な実装からのみ生じることを学びました。

次に、 Common Lisp vs.Schemeの記事からこのスニペットを見ました:

標準に従って、字句および動的の両方の字句スコープのみ。
スコープ付きの特殊変数。一般的な動的スコープの変数が提供されます
Lispはこの点で勝ちます。拡張機能としてのいくつかの実装による
                                  しかし、それらを使用するコードは移植性がありません。

     (動的スコープかどうかについての議論を聞いたことがあります
      そもそも悪い考えであるかどうか。私は気にしない。
      私はあなたがそれであなたが何かをすることができることに注意しているだけです
      それなしでは簡単にできません。)

Common Lispが「この点で勝つ」のはなぜですか?動的スコープで行うのが簡単なことは何ですか?私は本当にそれを必要とする/それを良いものとして見ることを正当化することはできません。

4

10 に答える 10

39

他のすべてと同様に、Dynamic Sc​​oping は単なるツールです。うまく使えば、特定の作業が簡単になります。不適切に使用すると、バグや頭痛が発生する可能性があります。

私は確かにそれのいくつかの用途を見ることができます. 一部の関数に変数を渡す必要をなくすことができます。

たとえば、プログラムの最初にディスプレイを設定すると、すべてのグラフィック操作はこのディスプレイを前提としています。

そのディスプレイ内にウィンドウを設定したい場合は、そのウィンドウを、別の方法でディスプレイを指定する変数スタックに「追加」できます。この状態で実行されたグラフィック操作は、ディスプレイとしてではなくウィンドウに移動します。全体。

これは、関数にパラメーターを渡すことによって同様にうまく実行できる不自然な例ですが、この種のタスクが生成するコードの一部を見ると、グローバル変数の方が実際にははるかに簡単な方法であることがわかります。関数パラメータの柔軟性を備えたグローバル変数の正気の多く

-アダム

于 2008-11-26T15:20:55.450 に答える
17

動的スコープの主なリスクは、意図しない結果です。動的スコープにより、スコープはランタイム スタックに従います。つまり、スコープ内のシンボルのセットははるかに大きく、シンボルが使用されている時点では明らかではありません。動的スコープ変数はグローバル変数によく似ていますが、各変数の複数のバージョンが存在し、最新の定義のみが表示され、他のすべてが隠されている場合があります。

動的スコープは、有用である限り、ランタイム スタックに敏感である必要がある動作に役立ちます。例 (そして一般的に言えば、Lisp やバリアントに固有のものではありません):

  • 例外処理 - 一番上の catch ブロックは、例外が発生したときに「スコープ内」にあるブロックです
  • セキュリティ - .NET コードベースのセキュリティは、特定の特権 API のアクセス可能性を、それを呼び出したコードに基づいて決定します。

他の用途に依存する場合の問題は、暗黙的な依存関係と、字句的に離れたコード間の結合を作成することです。このように、グローバル変数にも似ていますが、(動的にオーバーライドされた定義のために) 悪化する可能性があります。

于 2008-11-26T15:15:53.230 に答える
9

動的スコープは、一部のドメイン固有言語で役立ちます。特に、スタイルシート言語では便利です。私の経験は、GNU TeXmacsスタイルシート言語からのものです。

この言語では、表示パラメーターは動的スコープ変数に格納されます。これらの変数は、スコープ内で呼び出される関数によって生成されるアトムを含む、スコープ内のすべてのアトムのレンダリングに影響します。

TeXmacs の動的スコープは、特に相互参照のラベル付けにも使用されます。相互参照に使用されるアンカーは、その環境からラベルを取得します。たとえば、数式ブロックに含まれるアンカーは、数式の後にあるアンカーのセクション番号ではなく、数式番号をラベルとして使用します。

考えてみれば、UNIX 環境変数も動的スコープ変数です。ただし、内側のスコープは外側のスコープの変数の値を変更できません。

Barry Kellyが指摘したように、動的スコープは、例外処理やコンテキスト依存のパーミッション処理など、呼び出しスコープを考慮する言語機能の実装にも役立ちます。継続が存在する場合、呼び出しスタックをたどらずにスコープに出入りできます。

于 2008-11-26T15:15:33.043 に答える
7

動的スコープにより、コンテキスト関数の定義が可能になります。その意味で、これは最新のフレームワークにおける依存性注入に非常に似ています。(たとえば、さまざまな参照の透過的な初期化を可能にするために依存性注入定義を使用して Java クラスに注釈を付ける場合を検討してください。(Spring や JPA などを参照))

明らかに、動的スコープは、特定の関数の呼び出しサイトの実行時特性に関して、コンパイル (または設計) 時に保証できない特定の仮定を行います。繰り返しになりますが、最新の (Java) フレームワーク コンポーネントの例に従って、コンテナの制御された (ランタイム) 環境の外でそのようなクラスをインスタンス化すると、必要な依存関係を考えると、クラスが機能しなくなる可能性が高くなります。初期化されていません(別名注入)。

しかし、同じように明らかに、コンポーネント システム (一例として) は動的バインディング メカニズムの恩恵を受けます。依存性注入は、これを達成するためのフレームワーク レベルの手段です。動的スコープは、同じことの言語レベルの手段です。

于 2009-05-03T01:04:03.983 に答える
5

また、組み合わせることに注意してください

  • 語彙スコープの概念(動的スコープとは対照的に、プログラミング言語にとっては良いことだと私たちは感じています)
  • コードに深く埋め込まれた関数定義(ラムダ式)を使用する(このような定義を「ネストされた関数」と呼ぶこともできます)

言語実装の観点からも、プログラマーの観点からも、複雑な作業になる可能性があります。この複雑なものには特別な名前もあります:closure

ウィキペディアが書いているように:

ファーストクラスのネストされた関数 を使用する言語での静的スコープの正しい実装は、各関数値が依存する変数の値のレコードを保持する必要があるため、簡単ではありません(関数とこの環境のペアは呼び出されます)クロージャ)。

これは、グローバル変数や可変変数(CやJavaなど)を使用して言語で実装するのは簡単ではないだけでなく、その場所でスコープ内にあった可変状態へのクロージャの評価時に正しいアクセスを確保することを検討してくださいネストされた関数定義の1つだけです。将来、クロージャを評価するときに、使用されたオブジェクトが破棄されてガベージコレクションされるべきではありませんでした)が、プログラマーがどのように閉鎖は複雑な状況で機能しますそして、それが正確に持つ(副次的な)効果(同じ理由で:クロージャを定義したときにスコープ内にあったすべての可変状態とクロージャの相互作用について考える必要があります。例:クロージャ内を参照する場合スコープ内にある外部の可変変数への定義。クロージャの定義時に変数が持っていた値に本当にアクセスしたいですか。つまり、変数の読み取り専用コピーが必要ですか。クロージャの評価時に、将来的に変数の可変状態に本格的にアクセスしたいですか?)。

純粋関数型言語では、入れ子関数の定義とその使用法について考える方がはるかに簡単であるため、字句スコープのみを持つことはまったく問題になりません。しかし、あなたの言語が機能していなければ、それはそれほど些細なことではありません。(これが、Javaにクロージャーを追加する方法が長い間議論されてきた理由の1つだと思います。クロージャーは、字句スコープの優れた概念に基づいているだけですが、プログラマーが理解するのに十分なほど些細なことではないようです。 。)

純粋関数型でない言語でネストされた関数について考えることは、動的スコープを使用すると簡単になります(ただし、動的スコープは適切ではありません。コンパイル時のチェックが少なくなり、動的スコープを使用したプログラムの正しい動作が保証されます)。

したがって、言語で動的スコープを使用できることの利点は、動的スコープのすべての危険性を考慮して、これを実行したい場合に、簡単な方法でいくつかのことをプログラムできる可能性もあると思います。

ノート

Javaでの(ない)クロージャの長い歴史について(そしてプログラマーがその概念を気に入らなかったこと)-http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04030.html

日付:2003年8月14日木曜日08:05:44 -0700

差出人:Michael Vanier

件名:Re:バインディングと割り当て(以前は:Re:継続)

日付:2003年8月14日木曜日10:45:34 -0400

差出人:「DavidB.Tucker」

統計的な証拠はありませんが、匿名の内部クラス(クロージャ)内でローカル変数を参照するためにローカル変数を最終として宣言する要件はほとんど完全に不明であり、実際には使用されていないと思います。

好奇心から、Javaが匿名クラス内からの最終変数の参照のみを許可する理由を誰かが知っていますか?

デイブ

   <cynic>Otherwise you'd have the equivalent of true closures,
and if you had that    java would be a
*really* powerful and useful language, so they obviously    couldn't do that.
</cynic>

実際、プロトタイプの実装で 、内部クラス内から非最終変数を参照できました。これを望まないというユーザーからの抗議がありました!その理由は興味深いものでした。そのような変数をサポートするには、それらをヒープに割り当てる必要がありました。(少なくとも当時は)平均的なJavaプログラマーは、ヒープの割り当てやガベージコレクションなどについてまだかなり頭がおかしかったのです。彼らは、「new」キーワードの出現が見当たらないときに、「テーブルの下」でヒープ割り当てを実行する言語を承認しませんでした。

したがって、初期の頃は(明らかに)、Javaでは「3番目の」アプローチ(上記のテキストで言及した2つとは対照的)が採用されていました。「読み取り専用コピー」でも、実際のアクセスでもありません。評価から囲み(クロージャの定義時)の可変状態までの時間ですが、状態の可変コピー(少なくとも、引用された箇所をこのように理解しています;またはいいえ、彼はヒープ割り当てについて話しているのですか?参照だけですか?..それから2番目のオプションです。良いです。3番目のオプションは本当に私には意味がないように見えます。)彼らが最近Javaでクロージャをどのように実装しているかはわかりませんが、私はJavaに関する最近の新しい情報をフォローしていません。

于 2011-04-02T15:50:24.483 に答える
3

ダイナミック スコーピングは参照透過性を壊します。つまり、プログラムについてこれ以上推論することはできません。DS は基本的にステロイドのグローバル変数です。

于 2010-11-10T10:24:19.597 に答える
1

動的スコープの変数は強力ですが、直感的ではなく危険なツールでもあります。

スレッド固有のグローバル変数が必要だと想像してください。つまり、すべてのスレッドが独自のグローバル変数のセットを持っているとします。これは、動的スコープを使用して簡単に実行できます。スレッドの初期化時にこの変数への参照を変更するだけです。

または、例外について考えてみてください。例外はほとんどの言語で動的にスコープされます。ゼロから例外システムを構築する必要がある場合は、動的スコープ変数を使用して簡単に構築できます。

于 2009-05-03T01:54:26.670 に答える
0

Emacsのバインド方法で私にとって便利な例-ところで、レキシカルまたはダイナミックが正しい用語であるかどうかはわかりません。

let 内でバインドされた変数は下向きに表示され、引数として明示的に引き渡す必要がないため、多くのキーストロークが節約されます。

(defun foo1 ()
  (message "%s" a))

(defun foo2 ()
  (let ((a 2))
  (message "%s" a)))

(defun foo3 ()
  (let ((a 1))
    (foo1)
    (foo2)))

==>
1
2

デフォルト値の使用法がここにインストールされる可能性があるため、foo2 内のバインディングは興味深いものです。

(let ((a (if (eq something a) そうでなければ割り当て...

于 2013-08-24T06:17:04.530 に答える