Scala Функциональные литералы с имплицитами
Простите меня, если это уже было задано в другом месте. У меня есть вопрос с синтаксисом Scala, включающий функции-значения и неявные параметры.
Мне удобно использовать implicits с функцией Scala currying. Например, если у меня была функция sum и вы хотели сделать второй аргумент неявным:
scala> def sum(a: Int)(implicit b: Int) = a + b
sum: (a: Int)(implicit b: Int)Int
Есть ли способ сделать это, используя синтаксис функции-значения? Игнорируя неявное на какое-то время, я обычно пишу кардинальные значения функции следующим образом:
scala> val sum2 = (a: Int) => (b: Int) => a + b
sum: (Int) => (Int) => Int = <function1>
Однако сигнатура функции во втором подходе сильно отличается (каррирование выражается явно). Просто добавление неявного ключевого слова в b не имеет большого смысла, и компилятор также жалуется:
scala> val sum2 = (a: Int) => (implicit b: Int) => a + b
<console>:1: error: '=>' expected but ')' found.
val sum2 = (a: Int) => (implicit b: Int) => a + b
^
Кроме того, частично также применяется суммируемая сумма из самого первого подхода для получения функции-значения:
scala> val sumFunction = sum _
<console>:14: error: could not find implicit value for parameter b: Int
val sumFunction = sum _
^
Это заставляет меня полагать, что функции, которые имеют неявные параметры, должны иметь указанные параметры, определенные при создании значения функции, а не когда функция-значение применяется позже. Это действительно так? Можете ли вы использовать неявный параметр со значением функции?
Спасибо за помощь!
Ответы
Ответ 1
scala> val sum2 = (a: Int) => {implicit b: Int => a + b}
sum2: (Int) => (Int) => Int = <function1>
Это просто сделает b неявным значением для области тела функции, поэтому вы можете вызывать методы, ожидающие неявного Int.
Я не думаю, что у вас могут быть неявные аргументы для функций, так как тогда неясно, что это за функция. Это Int => Int
или () => Int
?
Самое близкое, что я нашел:
scala> case class Foo(implicit b: Int) extends (Int => Int) {def apply(a: Int) = a + b}
defined class Foo
scala> implicit val b = 3
b: Int = 3
scala> Foo()
res22: Foo = <function1>
scala> res22(2)
res23: Int = 5
Ответ 2
В этом фрагменте
scala> val sum2 = (a: Int) => (b: Int) => a + b
sum: (Int) => (Int) => Int = <function1>
Обратите внимание, что точный тип sum2
равен Function1[Int, Function1[Int, Int]]
. Его также можно записать как
val sum2 = new Function1[Int, Function1[Int, Int]] {
def apply(a: Int) = new Function1[Int, Int] {
def apply(b: Int) = a + b
}
}
Теперь, если вы попытаетесь сделать b
неявным, вы получите следующее:
scala> val sum2 = new Function1[Int, Function1[Int, Int]] {
| def apply(a: Int) = new Function1[Int, Int] {
| def apply(implicit b: Int) = a + b
| }
| }
<console>:8: error: object creation impossible, since method apply in trait Function1 of type (v1: Int)Int is not defined
def apply(a: Int) = new Function1[Int, Int] {
^
Или, другими словами, интерфейсы Function
не имеют неявных параметров, поэтому ничего с неявным параметром не является Function
.
Ответ 3
Попробуйте перегрузить метод apply.
scala> val sum = new Function1[Int, Function1[Int, Int]] {
| def apply(a: Int) = (b: Int) => a + b
| def apply(a: Int)(implicit b: Int) = a + b
|}
sum: java.lang.Object with (Int) => (Int) => Int{def apply(a:Int)(implicit b: Int): Int} = <function1>
scala> sum(2)(3)
res0: Int = 5
scala> implicit val b = 10
b: Int = 10
scala> sum(2)
res1: Int = 12