问题
I have a function exec which accepts 3 parameters and applies a function f passed as first argument to the other two - p1 and p2.
def exec[T](f: (T, T) => Boolean, p1: T, p2: T) = f(p1, p2)
Everything works fine if I declare in advance a function which will be passed as an argument.
Somehow compiler can infer types for arguments of eq or in other words it can figure out that whatever in this case is Int
// declaring a function with type parameter (polymorphic method)
def eq[whatever](p1: whatever, p2: whatever) = p1 == p2
// using a declared function
println(exec(eq, 10, 10))
It also works fine if I explicitly specify Int as shown below
// specifying type explicitly in function literal
println(exec((p1: Int, p2: Int) => p1 == p2, 10, 10))
// specifying type parameter
println(exec[Int]((p1, p2) => p1 == p2, 10, 10))
Question 1
Is it possible to get below working?
println(exec((p1, p2) => p1 == p2, 10, 10))
For example, by using implicits, defining exec differently or using some other way making it possible for compiler to infer types of p1 and p2 so that it does not fail with missing parameter type.
So no explicit type hints or declared methods are used.
Question 2
How does compiler infer types for eq and why it works for expressions like p1 == p2 or p1 != p2 but fails for p1 >= p2 (error is value >= is not a member of type parameter whatever)?
回答1:
Question 1 Is it possible to get below working?
If you can rewrite exec like this:
def exec[T](p1: T, p2: T)(f: (T, T) => Boolean) = f(p1, p2)
Then, the compiler will already know the input type of the function.
So, you will be able to call it like this:
println(exec(10, 10) { case (p1, p2) => p1 == p2 })
This is a common idiom, to put plain parameters first and then a function on a single parameter group.
How does compiler infer types for eq and why it works for expressions like p1 == p2 or p1 != p2 but fails for p1 >= p2
Because, Scala has universal equality (which is one of the things people most criticize of the language, but it was necessary for Java interop).
So, you can always compare two objects of any class for equality.
That is because equality is defined in the Any superclass as follows.
class Any {
def equals(other: Any): Boolean
}
But, ordering is not universal.
If you want, you may want to write a generic function which works for any type as long as there is an order for such type, you may be interested in the Ordering - typeclass.
But that is topic for another question.
回答2:
Scala 3 (dotty) will be able to infer the types in exec without having to rely on multiple parameter lists to help inference
scala> def exec[T](f: (T, T) => Boolean, p1: T, p2: T) = f(p1, p2)
| exec((p1, p2) => p1 == p2, 10, 10)
def exec[T](f: (T, T) => Boolean, p1: T, p2: T): Boolean
val res0: Boolean = true
来源:https://stackoverflow.com/questions/62123972/using-polymorphic-function-as-a-parameter