如何在类型推断中帮助Scala?

时间:2016-03-12 18:18:11

标签: scala type-inference

有时Scala无法推断出类型。这里的目标是了解原因并尝试帮助Scala做更好的推理。

用一个简单的例子可以更好地解释这个问题:

trait A
trait B

class G[Ao <: A, Bo <: B](a: Ao, b: Bo)

// This is my "complex" class with 3 type parameters
class X[Ao <: A, Bo <: B, Go <: G[Ao,Bo]](a: Ao, b: Bo, g: Go)

val a  = new A{}
val b  = new B{}
val g  = new G(a,b)

此处下面的OO类型是完美推断

class OO extends X(a,b,g) // Type of X[A,B,G[A,B]]

但是,如果我们将其中一个参数更改为一个选项(或任何集合),并且我们提供一个空集合(或None),则推理不起作用。

case class X[Ao <: A, Bo <: B, Go <: G[Ao,Bo]](a: Ao, b: List[Bo], g: Go)

class OO extends X(a,List(),g)

<console>:XX: error: inferred type arguments [A,Nothing,G[A,B]] do not conform to class X's type parameter bounds [Ao <: A,Bo <: B,Go <: G[Ao,Bo]]
       class OO extends X(a,List(),g)
                        ^
<console>:XX: error: type mismatch;
 found   : A
 required: Ao
       class OO extends X(a,List(),g)
                          ^
<console>:XX: error: type mismatch;
 found   : G[A,B]
 required: Go
       class OO extends X(a,List(),g)

这可以通过显式传递OO的所有参数来修复:

class OO extends X[A,B,G[A,B]](a,List(),g)

问题是,G已经有了它的类型,从X的定义我们看到G取X的前两个参数,所以如果我们知道G我们有我们需要的所有东西来推断X的参数。我可以做一些不同的事情来帮助Scala进行推理吗?我有一个比X更多参数的类,现在我总是要明确定义它们。我试图看看是否有什么可以帮助Scala成功推断出类型。

1 个答案:

答案 0 :(得分:3)

我猜你可以使用更高级的kinded类型:

case class X[Ao <: A, Bo <: B, Go[GAo <: Ao, GBo <: Bo] <: G[GAo, GBo]](a: Ao, b: List[Bo], g: Go[Ao, Bo])
class OO extends X(a,List(),g)

或者,如果您的类型参数是协变的:

case class G[+Ao <: A, +Bo <: B](a: Ao, b: Bo)
case class X[Ao <: A, Bo <: B, Go[_ <: Ao, _ <: Bo] <: G[Ao, Bo]](a: Ao, b: List[Bo], g: Go[Ao, Bo])

我从经验中知道,当scala编译器在相同组中的参数相互依赖时,它们不能推断出类型。&#34;不同的级别&#34;就像在这个例子中。较高的kinded类型允许我显式声明类型边界并帮助编译器推断出正确的类型。