3

私は昨夜プロジェクトに取り組んでいましたが、次のようなコードがありました。

/* fixes warnings in 2.10 */
import scala.language.implicitConversions

/* had some kind of case class with some members */
case class Wrapper[A](x: A)

/* for convenience's sake */
implicit def aToWrapper[A](x: A) = Wrapper(x)

/* had some kind of Seq */
val xs: List[Wrapper[String]] =  List("hello", "world", "this", "is", "a", "test")

それから私は誤って次のように書きました:

xs foldLeft("") { (a, x) => a + x }

.と の間を省略してxsいますfoldLeft

問題の型はもう少し複雑で、ラムダのパラメーター型に注釈を付けるように求められたので、それが私の間違いの原因だと考えて、すぐに注釈を付けました。私はこのようなものになりました:

xs foldLeft("") { (a: String, x: Wrapper[String]) => a + x }

この時点で、次のエラーが表示されました。

<console>:13: error: type mismatch;
found   : (String, Wrapper[String]) => String
required: Int
           xs foldLeft("") { (a: String, x: Wrapper[String]) => a + x }
                                                            ^

明らかに修正は でしたがxs.foldLeft("") ...、この場合、コンパイラがなぜ Int を期待しているのか疑問に思っていました。これがどのように解析されているかを誰かが明らかにできますか? これは一日中私を悩ませています。

4

2 に答える 2

2

ドットと括弧を省略すると、いわゆる中置記法が使用されます。a + bの代わりに書くことができますa.+(b)。ここでの重要なルールは、呼び出しが次の形式の場合にのみ許可されるということですobject method paramlist( SLS 6.12.3を参照)。

左結合演算子の右側のオペランドは、括弧で囲まれた複数の引数で構成される場合がありますe op (e 1 , ... , e n )。この式は として解釈されe.op(e 1 , ... , e n )ます。

foldLeftはこの形式に適合しないため、 を使用しますobject method paramlist1 paramlist2。したがって、これを演算子表記で記述すると、コンパイラは次のように扱います( SLS 6.12.2object.method(paramlist1).paramlist2で説明されているように)。

後置演算子は、任意の識別子にすることができます。後置操作e opは として解釈されe.opます。

ただし、ここで適用される別のルールがあります: Function Applications ( SLS 6.6 )。

アプリケーションf(e 1 , ... , e m)は、関数fを引数式に 適用しますe 1 , ... , e m

[...]

が何らかの値型を持っている場合f、アプリケーションは と等価であると見なされますf.apply(e 1 , ... , e m)。つまり、 によって定義された apply メソッドのアプリケーションですf

どうぞ:

scala> { (a, x) => a + x }
<console>:12: error: missing parameter type
              { (a, x) => a + x }
                 ^
<console>:12: error: missing parameter type
              { (a, x) => a + x }
                    ^

これは、型引数が欠落している単なる関数リテラルです。それらを追加すると、すべてが正常にコンパイルされます。

scala> { (a: String, x: Wrapper[String]) => a + x }
res6: (String, Wrapper[String]) => String = <function2>

コンパイラは、上記の関数適用に関する規則を適用するだけです。

scala> "" { (a: String, x: Wrapper[String]) => a + x }
<console>:13: error: type mismatch;
 found   : (String, Wrapper[String]) => String
 required: Int
              "" { (a: String, x: Wrapper[String]) => a + x }
                                                   ^

scala> "" apply { (a: String, x: Wrapper[String]) => a + x }
<console>:13: error: type mismatch;
 found   : (String, Wrapper[String]) => String
 required: Int
              "" apply { (a: String, x: Wrapper[String]) => a + x }
                                                         ^

したがって、コードは次のように解釈されます

scala> xs foldLeft ("").apply{ (a: String, x: Wrapper[String]) => a + x }
<console>:14: error: type mismatch;
 found   : (String, Wrapper[String]) => String
 required: Int
              xs foldLeft ("").apply{ (a: String, x: Wrapper[String]) => a + x }
                                                                      ^

しかし、なぜ関数適用規則を適用するのでしょうか? 関数リテラルを後置演算子として適用することもできます。表示されたエラー メッセージが表示される理由を確認するには、SLS Scala Syntax Summaryを確認する必要があります。そこでは、次のことがわかります。

  InfixExpr         ::=  PrefixExpr
                      |  InfixExpr id [nl] InfixExpr
  PrefixExpr        ::=  [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr 
  SimpleExpr        ::=  ‘new’ (ClassTemplate | TemplateBody)
                      |  BlockExpr
                      |  SimpleExpr1 [‘_’]
  SimpleExpr1       ::=  Literal
                      |  Path
                      |  ‘_’
                      |  ‘(’ [Exprs] ‘)’
                      |  SimpleExpr ‘.’ id 
                      |  SimpleExpr TypeArgs
                      |  SimpleExpr1 ArgumentExprs
                      |  XmlExpr
  Exprs             ::=  Expr {‘,’ Expr}
  ArgumentExprs     ::=  ‘(’ [Exprs] ‘)’
                      |  ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’
                      |  [nl] BlockExpr

上記のセクションから、ArgumentExprs関数の適用をInfixExpr説明し、中置式を説明していることがわかります。EBNFの規則により、最上位の規則の優先順位が最も低くなります。また、前者の規則は後者の規則によって呼び出されるため、関数リテラルが中置式の前に適用されることを意味し、エラー メッセージが表示されます。

于 2013-03-21T21:41:48.707 に答える
1

二項演算子は中置記法としてしか使用できないと思います。括弧を使用して状況を改善することもできると思います:(xs foldLeft( "")){(a:String、x:Wrapper [String])=> a+x}。おそらく、元のコードをとして解析しますxs.foldLeft("").{ (a: String, x: Wrapper[String]) => a + x }。この回答を確認してください:Scala中置記法で括弧を使用する場合

于 2013-03-21T20:38:47.213 に答える