15

Scala でプログラミングするとき、私はますます関数的なことをします。ただし、中置記法を使用する場合、括弧が必要な場合と不要な場合を区別するのは困難です。

たとえば、次のコードの一部:

def caesar(k:Int)(c:Char) = c match {
    case c if c isLower => ('a'+((c-'a'+k)%26)).toChar
    case c if c isUpper => ('A'+((c-'A'+k)%26)).toChar
    case _ => c
}

def encrypt(file:String,k:Int) = (fromFile(file) mkString) map caesar(k)_

(fromFile(file) mkString) は、コンパイルするために括弧が必要です。削除すると、次のエラーが表示されます。

Caesar.scala:24: error: not found: value map
    def encrypt(file:String,k:Int) = fromFile(file) mkString map caesar(k)_
                                                                 ^
one error found

mkString は明らかに、マップ関数を使用できる (暗黙的な変換による) 文字列を返します。

この特定のケースに括弧が必要なのはなぜですか? いつ、なぜそれが必要なのかについての一般的なガイドラインはありますか?

4

4 に答える 4

35

これは、仕様を読んだ後、私が自分でまとめたものです。

  • 単一のパラメーターをとる任意のメソッドを中置演算子として使用できます:a.m(b)と書くことができますa m b
  • パラメータを必要としないメソッドは、接尾辞演算子として使用できます:a.mと書くことができますa m

たとえば、書くことa.##(b)ができ、書くことができますa ## ba.!a!

  • 後置演算子は中置演算子よりも優先順位が低いため、foo bar bazfoo.bar(baz)whileをfoo bar baz bam意味し、は(foo.bar(baz)).bamfoo bar baz bam bim意味し(foo.bar(baz)).bam(bim)ます。
  • また、オブジェクトaのパラメーターなしのメソッドmが与えられた場合、は有効ですが、のように解析されるほどではありません。a.m.ma m mexp1 op exp2

単一のパラメーターをとるバージョンがあるためmkString、で中置演算子として表示されfromFile(file) mkString map caesar(k)_ます。mkString接尾辞演算子として使用できるパラメータをとらないバージョンもあります。

scala> List(1,2) mkString
res1: String = 12

scala> List(1,2) mkString "a"
res2: String = 1a2

適切な場所にドットを追加することで、必要な優先順位を取得できる場合があります。fromFile(file).mkString map { }

そして、その優先順位はすべて、入力や他のフェーズの前に発生するため、list mkString map functionとしては意味がありませんがlist.mkString(map).function、これが解析方法です。

于 2011-04-08T15:17:01.247 に答える
5

Scalaのリファレンスで言及されている (6.12.3: Prefix、Infix、および Postfix 操作)

連続する型中置演算のシーケンスではt0 op1 t1 op2 . . .opn tn、すべての演算子op1, . . . , opnが同じ結合性を持っている必要があります。
それらがすべて左結合である場合、シーケンスは として解釈され(. . . (t0 op1 t1) op2 . . .) opn tnます。

あなたの場合、「map」は演算子「mkstring」の用語ではないため、グループ化が必要です (「fromFile(file) mkString」を括弧で囲みます)。


実際、Matt Rは次のようにコメントしています。

それは実際には結合性の問題ではなく、「後置演算子は常に中置演算子よりも優先順位が低くなります。たとえばe1 op1 e2 op2、常に " と同等(e1 op1 e2) op2です。(同じく 6.12.3 から)

huynhjl回答(賛成) は詳細を示し、Mark Bush回答(同じく賛成) は「A Tour of Scala: Operators」を指して、「単一のパラメーターを受け取るメソッドはすべて中置演算子として使用できる」ことを示しています。 .

于 2011-04-08T10:39:18.327 に答える
4

簡単なルールは次のとおりです。接尾辞演算子は使用しないでください。その場合は、式全体を括弧内に接尾辞演算子で終了します。

実際、Scala 2.10.0以降、これを行うとデフォルトで警告が生成されます。

適切な方法として、接尾辞演算子を移動し、ドット表記を使用することをお勧めします。例えば:

(fromFile(file)).mkString map caesar(k)_

または、さらに簡単に、

fromFile(file).mkString map caesar(k)_

一方、空の括弧を指定して中置に変換できる方法に注意してください。

fromFile(file) mkString () map caesar(k)_
于 2011-04-08T19:01:10.200 に答える
2

仕様では明確にされていませんが、私の経験と実験から、Scala コンパイラーは常に中置記法を使用するメソッド呼び出しを中置演算子として処理しようとすることがわかっています。mkString の使用は後置ですが、コンパイラはそれを中置として解釈しようとするため、「マップ」をその引数として解釈しようとしています。後置演算子のすべての使用は、直後に式ターミネータが続くか、コンパイラがそれを認識できるように「ドット」表記で使用する必要があります。

これについては、 A Tour of Scala: Operators でヒントを得ることができます (詳しくは説明されていませんが) 。

于 2011-04-08T13:44:15.647 に答える