1

Lisp (私はまだ SBCL で Lisp を学んでいます) では、ローカル変数は で宣言されlet、スコープはその式内のみです。何故ですか?C/C++/Java などの他の命令型言語とは異なり、関数スコープ内のどこでもローカル変数を自由に使用できます。

4

3 に答える 3

6

let とは何かについてのちょっとした洞察です。これは基本的に、「逆向きに綴られた」無名関数のアプリケーションです。

JavaScript はより C に似た言語であり、概念を非常によく示しているため、説明に JavaScript を使用します。

(function(variableA, variableB){
  console.log("variableA = " + variableA);
  console.log("variableA * variableB = " + variableA * variableB);})(6, 7);

それでは、パーツに名前を付けましょう。from functionto;}は関数定義です。(definition)(arguments)アプリケーションです。Let 式は基本的に同じことを行います。つまり、無名関数を引数付きで呼び出し、その関数内で変数として使用します。したがって、前の例を考えると、それを let 形式で書き直すと、次のようになります。

(let(variableA = 6, variableB = 7){
  console.log("variableA = " + variableA);
  console.log("variableA * variableB = " + variableA * variableB);});

(JavaScript はまだ let をサポートしていないため、上記は実際のコード例ではありませんが、例として示す必要があります)

また、それほど単純ではないことにも注意してください。より複雑なケースでは、別の引数を作成するときに引数の 1 つを参照したい場合があるため、 を(let* ...)使用するか、この式の引数として関数を使用したい場合に or を使用し(flet ...)ます(labels ...)。しかし、一般的な考え方は同じです。

于 2012-05-01T09:08:02.177 に答える
4

Lisp には、ローカル変数を導入するための構造があります。スコープを設定します。フォームが許可されている場所ならどこでも使用できます。そのための 2 つの主な構造は、LET と LET* です。Ait を使用すると、関数とは別にローカル変数を定義できます。ローカル変数が必要な場合は関数を導入する必要はなく、ローカル変数を最小限のスコープにするために使用します。

また、DEFUN を使用するとローカル変数を宣言できることにも注意してください。これにより、パラメーター リスト内の &AUX でそれらを導入できます。

于 2012-05-01T07:41:56.213 に答える
3

とあなたが言及している他のスタイルの違いはlet、純粋に構文糖衣の 1 つです。「どこでも」新しい変数を導入できる言語では、ネストされたスコープがまだありますが、表面の構文でフラット化されるだけです。例えば

{
  x = 3;
  x++;
  y = 4;
  print "hi";
  z = 42;
}

ここにはスコープが 1 つだけではなく、さまざまなスコープがあります。xで始まるスコープがありますx = 3y次に、で始まるスコープがありますy = 4yそのスコープの前を参照すると、エラーが発生します。

この種のことは、コードを処理するコードの開発に多くの労力を追加するため、Lisp から除外されています。そのような言語のコンパイラは、そのコードを分析し、ネストされたlet構造を示す抽象構文ツリー構造を復元する必要があります。これにより、コンパイラの残りのパスは、その情報を再発見するためにコードを再分析し続ける必要がなくなります。

Lisp では、その抽象構文ツリー構造に直接書き込みます。これにより、言語が統一されます。すべてがフォームであり、それが複合フォームの場合は、左端の位置に演算子があり、そのフォームの残りの部分の意味を文脈に依存しない方法で決定します。

たとえば、この最近の質問を参照してください: find free variables in lambda expression . ラムダ式の自由変数を見つけることは、 などの特殊な形式をバインドするletか、そのような特殊な形式の小さなレパートリーに展開するマクロによって開始される場合、はるかに簡単になります。

また、関数型スタイルは、とにかく Lisp によって強制されるわけではありませんが、これらの種類の言語よりも一般的であることに注意してください (架空の「{} 言語」の変数定義の中に命令文があることに注意してください)。命令文がない場合、実際にこれに遭遇することはありません。

機能コードでは、次の形式で連続バインディングを使用できlet*ます。

(let* ((x 1)                    x = 1;
       (y (1+ x))               y = x + 1;
       (z (/ x y))              z = x / y;
  (sqrt z))                     return sqrt(z);

の後の初期化はlet*、以前のバインディングを参照できます。

于 2012-05-03T19:15:09.233 に答える