1

プロジェクトのために JavaScript を学ばなければなりませんでした。(ただし、デスクトップだけでなく、サーバーやモバイルの分野でも同様に、その使用とその影響の大きさを認識しています)。多くの文献で繰り返されていることの 1 つは、「グローバル名前空間を汚染しない」ことであり、多くの合理的な 理由があります。

私が理解していることから、スキームはlisp-1であり、reason、 like thisなどがあります

  1. スキームのグローバル変数の規則は何ですか?
  2. グローバル変数とローカル変数を使用する際に注意すべき落とし穴はありますか? (特に、それ自体はエラーをスローしないが、目に見えないバグを引き起こす可能性があるもの)。
4

2 に答える 2

3

最初の質問ですが、Scheme にはグローバルに関する単一の規則はありません。*foo*(上のコメントで述べたように、CL の同じ命名規則とは異なる理由で)使用する人もいれば、大文字を使用する人もいますが(大文字と小文字を区別するスキームで)、どちらも慣習と見なされるほど一般的ではありません。

2 番目の質問は、より微妙です。はい、単一のグローバル名前空間を持つことには落とし穴があります。これらの落とし穴は、JavascriptやCommon Lispの落とし穴と同じです。ランダムなコードをロードすると、他のコードの意味が変わる可能性があるという事実です。つまり、2 つのライブラリをロードし、両方で何らかのfooグローバル関数を定義したい場合は、これらのライブラリのうち、他のライブラリを壊します。これは新しい問題ではなく、さまざまな対処方法があります。

最も明白なことは、パブリック インターフェイスの一部ではないグローバルを使用しないようにすることです。したがって、たとえば、代わりに

(define helper ...)
(define foo ...)

あなたが書く

(define foo
  (let ()
    (define helper ...)
    (define foo ...)
    foo))

インターフェイスに複数の関数がある場合は、同様のことを行います (たとえば、Racketdefine-valuesを使用したり、関数のリストを使用したりします)。これには二重の保護があることに注意してください。helperグローバル名前空間を汚染しないため、他のコードを壊さないなどの内部的なものと、 を定義する他のコードがhelperこのコードを壊すことはありません。これにはfoo、再帰的に自分自身を呼び出す場合も含まれます。

関連するハックは、高速にしたい場合にそのようなコードを作成することです。最初のバージョンではfoo、バインドが後で変更される可能性があるため、Scheme コンパイラは高速ループにコンパイルできませんが、2 番目のバージョンでは、そのような最適化が可能です。

モジュール システムがない場合の防御的プログラミングのもう 1 つの形式は、コードにとって重要な値を取得することです。たとえば、次のようにできます。

(define foo
  (let ([+ +] [- -] [* *] [/ /] ... more ...)
    (define helper ...)
    (define foo ...)
    foo))

そして今、コードは算術演算への独自の不変のバインディングを持っています。これにより、将来これらの演算が変更されないように保護され、このコードでの算術演算の安全な最適化が可能になります。

(function() { ... })()これらはすべて、Javascriptでの の一般的な使用法に似た、貧乏人のモジュール システムの慣例のようなものです。しかしもちろん、適切なモジュール システムを使用すると、これがより便利になり、適切に動作します。新しいJavascriptバージョンと新しいSchemeバージョンの両方が、ある種のモジュールシステムでこの問題に直面しており、Schemeでは、モジュールのみを使用loadし、信頼できないハックとして回避する傾向があります.

(また、Common Lisp について言及したので、他のファイルからグローバル変数や関数を上書きしている可能性があるため、同じ問題があることがわかります。これに対処する方法は、CL のパッケージ システムを使用することです。モジュールシステム. モジュールシステムが弱い理由は, 別の名前空間の利便性を提供することです.つまり、コンパイラは、バインディングが変更されないことをまだ想定できません)。

于 2013-04-30T06:26:19.063 に答える
2

Scheme に 'lisp-2' を含めることができます。一貫した文字セットを使用してすべての機能を優先するだけです。RnRS で定義されている関数を再バインドすることから始めることができます。このような:

(define this-is-a-scheme-function-+ +)
(define this-is-a-scheme-function-call-with-current-continuation call-with-current-continuation)

ただし、慣例により、

(define tiasf-call/cc this-is-a-scheme-function-call-with-current-continuation)
于 2013-04-29T20:15:39.727 に答える