Вы можете использовать -Xprint:parser
, чтобы увидеть, что парены сбрасываются раньше:
scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x
scala> "hi".scaled(5)
res0: String = hihihihihi
scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi
scala> "hi".scaled(5)(3)
res2: Char = i
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi
scala> :se -Xprint:parser
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of parser]] // <console>
package $line8 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.x;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res4 = {
implicit val n: Int = 5;
"hi".scaled(3)
}
}
}
}
}
res4: String = hihihi
scala>
Дополнительные парены ничего не делают. Компилятор просто видит приложение expr(args)
. Поскольку это приложение, вы не получаете преобразование «неявное приложение».
В любом случае значение scaled
, метода, зависит от ожидаемого типа.
Причина, по которой мы ожидаем, что дополнительные парены будут иметь значение, состоит в том, что парены переопределяют приоритет операторов. Но (x)
это просто x
.
Возможно, спецификация на самом деле ясна по этому поводу:
e(args)
требует, чтобы e
был применим к args
. В частности, аргументы проверяются по типу в соответствии с типами параметров e
.
e(args)
принимается как e.apply(args)
, если e
является значением, но scaled
является методом.
Вы надеетесь, что «неявное приложение» вставит неявные аргументы, но это применимо, только если e
еще не применено. Или что (e)(args)
можно принять за (e(_))(args)
, то есть (x => e(x))(arg)
.
Если записано как e.apply(arg)
, e
не является приложением, подобным e(arg)
, поэтому вы получаете выгоду от преобразований, таких как неявное приложение.