I have several generic functions with the same signature:
def f1[A, B](v: A, f: (A, B) => B): B = ...
def f2[A, B](v: A, f: (A, B) => B): B = ...
And I need to define a function g
that can accept any of these functions (f1
f2
):
def g(f: ????) = ...
g
internally uses multiple argument types, so I can not parameterize it like that:
def g[A, B](f: (A, (A, B) => B) => B) = ...
CodePudding user response:
There isn't really a much better way to do it in Scala 2. Although your solution is a bit strange because FunctionHolder
's apply
method will return a function object and doesn't accept any arguments itself – that's a bit more complicated than it needs to be. So you can do this instead:
trait FunctionHolder {
def apply[A, B](v: A, f: (A, B) => B): B
}
def g(f: FunctionHolder) = …
But this isn't really all that much better.
In Scala 3, there are polymorphic function types to do this in a cleaner way:
def g(f: [A, B] => (A, (A, B) => B) => B) = …
That said, I'm not convinced that that type signature is really what you want. Remember, when you define a function with type parameters, it needs to work for all possible type parameters that the user might supply. This can't be done for this signature…
def f1[A, B](v: A, f: (A, B) => B): B
… because when I have a function like that, I can easily write an expression of type Nothing
:
f1[Unit, Nothing]((), (a: Unit, b: Nothing) => b)
and it's not possible to write an expression of type Nothing
unless you cheat (e. g. throw an exception or enter an infinite loop or something like that). So the type signature tells me you're cheating