Reputation: 3982
I would like to define a function that takes one explicit and one implicit parameter, like so:
def foo(a: Int)(implicit b: Int) : Int
but as a class or object, like so
object Foo extends ((Int,Int) => Int) {
def apply(a: Int)(implicit b: Int) : Int = { ... }
}
so that the function can be called like this:
implicit val b = 2
val g = Foo(1)
I fail to get the declaration of the base from which class Foo
should extend right.
How can this be done?
Upvotes: 2
Views: 663
Reputation: 36
A question is: Why do you need necessarily to pass that object Foo to "where an (Int,Int) => Int is expected" ?
I suppose that object Foo shall have some more special features which does exhance it beyond being a function?
It seems better to separate two concerns here: a) The function (Int)(implicit Int) => Int and b) the object Foo
object Foo {
def apply(a: Int, b: Int) : Int = { ... }
}
def foo(a: Int)(implicit b: Int) : Int = Foo(a, b)
implicit val m:Int = 42
foo(5) // --> res1: Int = 47
You may consider 'foo' a "companion function" if you like ...
Beside that: I suppose trying to apply an (Int)(implicit Int)=>Int "where an (Int,Int) => Int is expected" may not work, as these types are not identical. At least when you try to put that into a
def bar(f:(Int,Int)=>Int) = ....
The method bar would call its parameter f with two arguments anyway, as it expects it to take two, and cannot assume that the provided function in f is indeed able to work with implicits.
Upvotes: 0
Reputation: 51109
Rather than extending (Int, Int) => Int
you could use an implicit conversion:
class Foo(f: (Int, Int) => Int) {
def apply(a: Int)(implicit b: Int) : Int = f(a, b)
}
implicit def Foo_to_Function2(foo: Foo) = (x: Int, y: Int) => foo(x)(y)
Test:
val foo = new Foo(_ * 10 + _)
foo(4) //error since no implicit Int yet
{
implicit val impint = 5
foo(4) //45
}
def takesF2(f: (Int, Int) => Int) = f(1, 2)
takesF2(foo) //12 - works as normal Function2
Upvotes: 0
Reputation: 10852
So there are two parts to this question - firstly, how does one create an object that implements a function with a curried parameter list. And then, how does one make one of those parameter lists implicit.
The first of those is definitely possible. Note that a curried function is a function that returns a function. So f(x: Int)(y: Int)
is actually a Function1
, not a Function2
:
scala> def f(x: Int)(y: Int) = x + y
f: (x: Int)(y: Int)Int
scala> f _
res0: Int => Int => Int = <function1>
And you can certainly create a class that implements this:
scala> object Foo extends (Int => Int => Int) {
| def apply(x: Int) = {(y: Int) => x + y}
| }
defined module Foo
scala> Foo(1)(2)
res1: Int = 3
Unfortunately, I'm not aware of any way to make the second parameter list implicit.
Upvotes: 0
Reputation: 3722
You cannot. Function2[T1, T2, R] declares the abstract method apply(t1: T1, t2: T2): R, so if you want to mix in Function2, you have to implement this arity-2 apply method, which has a different signature than the curried version you would like to use.
Upvotes: 5