Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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) = ...
like image 324
michael nesterenko Avatar asked Mar 01 '23 08:03

michael nesterenko


1 Answers

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!”

like image 128
Matthias Berndt Avatar answered Mar 07 '23 10:03

Matthias Berndt