Generic nested type inference works with arity-2 b

2019-08-20 03:35发布

问题:

Trying to figure out why the code compiles for nested type inference on method with arity-2 but not with currying.

object Test
{
    trait Version
    object VersionOne extends Version

    trait Request[A <: Version]
    trait RequestOne extends Request[VersionOne.type]

    case class HelloWorld() extends RequestOne

    def test1[A <: Version, T <: Request[A]](t : T, a : A): T = t
    def test2[A <: Version, T <: Request[A]](t : T)(a : A): T = t
}

// This works
Test.test1(Test.HelloWorld(), Test.VersionOne)

// This doesn't
Test.test2(Test.HelloWorld())(Test.VersionOne)

test2 fails to compile with the following error:

Error:(22, 73) inferred type arguments [Nothing,A$A96.this.Test.HelloWorld] do not conform to method test2's type parameter bounds [A <: A$A96.this.Test.Version,T <: A$A96.this.Test.Request[A]] def get$$instance$$res1 = /* ###worksheet### generated $$end$$ */ Test.test2(Test.HelloWorld())(Test.VersionOne)

Looking forward to some insights on the same.

回答1:

@DmytroMitin already explained why it does fail.

However, you can solve the problem this way, using the Partially-Applied Type trick, together with Generalized Type Constraints.

def test2[T](t: T): Test2PartiallyApplied[T] = new Test2PartiallyApplied(t)

final class Test2PartiallyApplied[T](private val t: T) extends AnyVal {
  def apply[A <: Version](a: A)(implicit ev: T <:< Request[A]): T = t
}

Which you can use like this.

Test.test2(Test.HelloWorld())(Test.VersionOne)
// res: HelloWorld = HelloWorld()


回答2:

Nothing in compile error usually means that some type parameters were not inferred.

Try to specify them explicitly

Test.test2[Test.VersionOne.type, Test.RequestOne](Test.HelloWorld())(Test.VersionOne)

Difference between test1 and test2 is not only in currying. For example, generally in test2(t: ...)(a: ...) type of a can depend on value of t. So for test2 type inferrence is more complicated than for test1.

Scala type inference and multiple arguments list

Type inference with type aliases and multiple parameter list function

Multiple parameter closure argument type not inferred

What's the difference between multiple parameters lists and multiple parameters per list in Scala?