Когда вы опускаете точку и круглые скобки, вы используете так называемую инфиксную нотацию. Он позволяет вам писать a + b
вместо a.+(b)
. Важное правило здесь является то, что это разрешено только, если вызов имеет вид object method paramlist
(см SLS 6.12.3):
The right-hand operand of a left-associative operator may consist of several arguments enclosed in parentheses, e.g. e op (e 1 , ... , e n)
. This expression is then interpreted as e.op(e 1 , ... , e n)
.
foldLeft
не вписывается в эту форму, он использует object method paramlist1 paramlist2
. Таким образом, если вы пишете это в операторной записи компилятор воспринимает его как object.method(paramlist1).paramlist2
(как описано в SLS 6.12.2):
A postfix operator can be an arbitrary identifier. The postfix operation e op
is interpreted as e.op
.
Но есть еще одно правило применяется здесь: Функция Приложения (SLS 6.6).
An application f(e 1 , ... , e m)
applies the function f
to the argument expressions e 1 , ... , e m
.
[...]
If f
has some value type, the application is taken to be equivalent to f.apply(e 1 , ... , e m)
, i.e. the application of an apply method defined by 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 самое верхнее правило имеет самый низкий приоритет. И поскольку первое правило вызывается последним, это означает, что функциональный литерал применяется перед выражением инфикса, следовательно, сообщение об ошибке.
Благодарим вас за подробный ответ, который имеет прекрасный смысл только с вашим последним примером, но выдержки из SLS добавляют еще больший контекст. – jroesch