如果指定type-parameter,为什么此Scala代码会挂起?

时间:2013-09-02 15:36:15

标签: scala implicit-conversion scala-2.10 type-level-computation

最近,我在Scala中使用了类型级编程,并发现了以下内容:

trait NextPage[Curr, Next] {
  def next : Next
}

class Foo
class Bar

class X(val year : Int)

object X {
  implicit def xToNextPage[Y](x : X) : NextPage[X, Y] =
    if (x.year == 2010) {
      new X(x.year) with NextPage[X, Bar] {
        def next = new Bar 
      }
    }
    else {
      new X(x.year) with NextPage[X, Foo] {
        def next = new Foo
      }
    }
}

val x = new X(2010)
val y = x.next //BOOM!

最后一行无限期冻结了解释器。有什么奇怪的,如果你只改变一行代码:

implicit def xToNextPage[Y](x : X) : NextPage[X, Y] =

到那个

implicit def xToNextPage(x : X) : NextPage[X, _] =

计算将成功执行(但结果类型将丢失,当然)。

你知道为什么会这样吗?我相信,它以某种方式与类型推理有关......

2 个答案:

答案 0 :(得分:2)

原因是由于隐式转换,它处于无限递归状态。从implicit移除xToNextPage关键字,它会显示错误:

<console>:29: error: type mismatch;
 found   : X with NextPage[X,Bar]
 required: NextPage[X,Y]
             new X(x.year) with NextPage[X, Bar] {

显然,您的函数声明表明您正在返回NextPage[X, Y],但实际上您返回NextPage[X,Any]

它是递归的,因为当标记为implicit时,因为函数返回类型是[X, Y]。但是因为您要返回[X,Any],它会再次调用隐式函数xToNextPage来尝试转换它。

解决方案:将声明更改为:

trait NextPage[Curr, +Next] {
  def next : Next
}
implicit def xToNextPage[Y](x : X) : NextPage[X, Any]

答案 1 :(得分:0)

我不确定你在这里要做什么。我对Scala中的类型级编程没有任何经验,但这对我来说看起来不像正确的类型级编程。您在Y中使用类型参数xToNextPage[Y](x : X)尝试实现的目标是什么? Next[X, Y]唯一可能的值是Next[X, AnyRef],因为FooBar的最小共同祖先是AnyRef。摆脱Y会给你唯一正确答案:

trait NextPage[Curr, Next] {
  def next : Next
}

class Foo
class Bar

class X(val year : Int)

object X {
  implicit def xToNextPage(x : X) =
    if (x.year == 2010) {
      new X(x.year) with NextPage[X, Bar] {
        def next = new Bar 
      }
    }
    else {
      new X(x.year) with NextPage[X, Foo] {
        def next = new Foo
      }
    }
}

val x = new X(2010)
val y = x.next // => y: Object = Bar@6704e2a0

我不认为这真的能回答你的问题,但我认为这可能会有所帮助。我很想知道其他人是否可以提出一个实际推断y: Bar的解决方案,但我认为这超出了类型系统的限制。