Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
623 views
in Technique[技术] by (71.8m points)

scala - Multiple parameter closure argument type not inferred

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 Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...