Forgive me if this has already been asked elsewhere. I have a Scala syntax question involving function-values and implicit parameters.
I'm comfortable using implicits with Scala's currying feature. For instance if I had a sum function and wanted to make the second argument an implicit:
scala> def sum(a: Int)(implicit b: Int) = a + b
sum: (a: Int)(implicit b: Int)Int
Is there a way to do this using the function-value syntax? Ignoring the implicit for a moment, I typically write curried function-values like this:
scala> val sum2 = (a: Int) => (b: Int) => a + b
sum: (Int) => (Int) => Int = <function1>
However, the function signature in the second approach is much different (the currying is being expressed explicitly). Just adding the implicit keyword to b doesn't make much sense and the compiler complains as well:
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
^
Furthermore partially-applying sum from the very first approach to get a function-value causes problems as well:
scala> val sumFunction = sum _
<console>:14: error: could not find implicit value for parameter b: Int
val sumFunction = sum _
^
This leads me to believe that functions that have implicit parameters must have said parameters determined when the function-value is created, not when the function-value is applied later on. Is this really the case? Can you ever use an implicit parameter with a function-value?
Thanks for the help!
scala> val sum2 = (a: Int) => {implicit b: Int => a + b}
sum2: (Int) => (Int) => Int = <function1>
This will just make b an implicit value for the scope of the function body, so you can call methods that expect an implicit Int.
I don't think you can have implicit arguments for functions since then it is unclear what the function is. Is it Int => Int
or () => Int
?
The closest I found is:
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
In this snippet
scala> val sum2 = (a: Int) => (b: Int) => a + b
sum: (Int) => (Int) => Int = <function1>
Note that the precise type of sum2
is Function1[Int, Function1[Int, Int]]
. It could also be written as
val sum2 = new Function1[Int, Function1[Int, Int]] {
def apply(a: Int) = new Function1[Int, Int] {
def apply(b: Int) = a + b
}
}
Now, if you try to make b
implicit, you get this:
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] {
^
Or, in other words, Function
's interfaces do not have implicit parameters, so anything with an implicit parameter is not a Function
.
Try overloading the apply method.
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