web-dev-qa-db-ja.com

Scala "<-"理解のために

Scalaは常に何かに対して「自然な説明」を持っていることがわかりました。常に「ああ、でもこれとそのオブジェクトでこれとそのパラメータを使って呼び出される関数です」のようなものです。ある意味、他の言語から知っているように、実際にはコンパイラの魔法はありません。

私の質問は、次のコードで使用されている<-演算子に関するものです。

for(i <- 0 to 10) println(i)

この例では、次のように書き換えられていることがわかります。

0.to(10).foreach((i:Int)=>println(i))

しかし、これはiがforeach関数内の無名関数にどのように持ち込まれたかを説明していません。 iと書いた時点では、それはオブジェクトではなく、まだ宣言された変数でもありません。それで、それは何ですか、そしてそれはどのようにforeachの内部に持ち越されますか?

私の推測では、私はついに実際にコンパイラの魔法である何かを発見したと思います

御時間ありがとうございます。

明確にするために私の質問は次のとおりです。iは関数として呼び出すことができるオブジェクトではないため、コードの1行目で<-演算子はどのように機能しますか。

24
Felix

<-は、=>と同様に、言語で定義されたキーワードシンボルですが、->(定義されたシンボル)とは明らかに対照的です。これは基本的なScala文法の一部であるため、ユーザー定義では実行できないバインディング(この例ではiの場合)を作成するために使用できます。コンストラクト。

18
Randall Schulz

Daveの答えを補強するために、ここにScala言語仕様からの 'for-comprehensions'の翻訳スキーマがあります:

内包表記for (enums) yield eは、列挙型列挙型によって生成された各バインディングの式eを評価します。列挙子シーケンスは常にジェネレーターで始まります。この後に、さらにジェネレーター、値定義、またはガードを続けることができます。

ジェネレーター_p <- e_は、式eからバインディングを生成します。これは、パターンpに対して何らかの方法で照合されます。値の定義_val p = e_は、値の名前p(またはパターンpの複数の名前)を式eの評価結果にバインドします。ガード_if e_には、列挙されたバインディングを制限するブール式が含まれています。

ジェネレーターとガードの正確な意味は、mapfilterflatMap、およびforeachの4つのメソッドの呼び出しへの変換によって定義されます。これらのメソッドは、さまざまなキャリアタイプに対してさまざまな方法で実装できます。

翻訳スキームは次のとおりです。最初のステップでは、すべてのジェネレーター_p <- e_(pはeのタイプに対して反駁できない(§8.1))は次のように置き換えられます。

_ p <- e.filter { case p => true; case _ => false }
_

次に、すべての理解がなくなるまで、次のルールが繰り返し適用されます。

  • 理解のためのfor (p <- e) yield e0は_e.map { case p => e0 }_に翻訳されます。

  • 理解のためのfor (p <- e) e0は_e.foreach { case p => e0 }_に翻訳されます。

  • 理解のためのfor (p <- e; p0 <- e0 . . .) yield e00、ここで。 。 。ジェネレータまたはガードの(おそらく空の)シーケンスであり、次のように変換されます。
    e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }

  • For-comprehension for (p <- e; p0 <- e0 . . .) e00where。 。 。ジェネレータまたはガードの(おそらく空の)シーケンスであり、次のように変換されます。
    e.foreach { case p => for (p0 <- e0 . . .) e00 }

  • ジェネレーター_p <- e_の後にガード_if g_が続くと、単一のジェネレーターに変換されます。
    p <- e.filter((x1, . . . , xn) => g )
    ここで_x1_、。 。 。 、xnpの自由変数です。

  • ジェネレーター_p <- e_の後に値定義_val p0 = e0_が続くと、値のペアの次のジェネレーターに変換されます。ここで、xと_x0_は新しい名前です。

    _val (p, p0) <- 
      for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
    _
59
missingfaktor

この場合、それは本当にコンパイラの魔法のビットです。 for-comprehensionからfilter/map/flatmap形式への変換は、updateおよびapplyメソッドの特別な形式の変換と同様に、特別な脱糖です。

7
Dave Griffith