I have a piece of code that I can't get to behave in the way I'd like. I have a class defined in the following way (stripped down for this):
class Behaviour[T](private val rule: Time => T) {
def map1[U, V](behaviour: Behaviour[U], func: (T, U) => V): Behaviour[V] = {
new Behaviour(time => func(this.at(time), behaviour.at(time)))
}
}
When playing around with this class I tried to something that I thought would be trivial:
val beh = Behaviour(time => 5)
val beh2 = Behaviour(time => 5)
beh.map1(beh2, (a, b) => a + b)
For the last line I receive the following error:
<console>:13: error: missing parameter type
beh.map1(beh2, (a, b) => a + b)
^
I can of course specify the closure parameter types and it works correctly but why doesn't type inference work here? Of course I could also specify the generic types for the function (see below for both solutions).
I thought Scala carried out a 'scan' to infer types and would see beh2
and passed into the function and assume U
here to be Int
. Is there some way I can fix this without specify the types of the input parameters (for the closure or the generics)?
EDIT: Examples of the two fixes I have:
beh.map1[Int, Int](beh2, (a, b) => a + b)
beh.map1(beh2, (a, b : Int) => a + b)
See this scala-debate
thread for a discussion of what's going on here. The problem is that Scala's type inference happens per parameter list, not per parameter.
As Josh Suereth notes in that thread, there's a good reason for the current approach. If Scala had per-parameter type inference, the compiler couldn't infer an upper bound across types in the same parameter list. Consider the following:
trait X
class Y extends X
class Z extends X
val y = new Y
val z = new Z
def f[A](a: A, b: A): (A, A) = (a, b)
def g[A](a: A)(b: A): (A, A) = (a, b)
f(y, z)
works exactly as we'd expect, but g(y)(z)
gives a type mismatch, since by the time the compiler gets to the second argument list it's already chosen Y
as the type for A
.
One of the ways to fix this is to define multiple argument lists. So your map1
method would be defined like this:
def map1[U, V](behaviour: Behaviour[U])(func: (T, U) => V): Behaviour[V] = ...
and you can use it like this:
beh.map1(beh2)((a, b) => a + b)
beh.map1(beh2)(_ + _)
I'm not completely sure why type inference does not work in your case, but I believe that it has something to do with usage of U
type parameter. You are using it twice - for the first and second argument. It's probably too complicated for compiler to figure it out. In case of 2 argument lists, U
would be inferred during first argument list compilation, and the second argument list will use already inferred type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With