michael nesterenko
michael nesterenko

Reputation: 14439

scala generic function reference

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) = ...

Upvotes: 4

Views: 92

Answers (2)

Matthias Berndt
Matthias Berndt

Reputation: 4587

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 😉

If you want to know more about this kind of reasoning, search for “Theorems for free!”

Upvotes: 7

michael nesterenko
michael nesterenko

Reputation: 14439

After wandering a bit, come up with following:

g(new FunctionHolder {
    def apply[A, B](): (A, (A, B) => B) => B = f1
})


def g(f: FunctionHolder) = f()(..., (a, b) => ...)

abstract class FunctionHolder {
    def apply[A, B](): (A, (A, B) => B) => B
}

But that just does not look right.

Hope there are more concise ways to do that

Upvotes: 0

Related Questions