1

最近,我在 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, _] =

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

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

4

2 回答 2

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]
于 2013-09-02T18:07:25.717 回答
0

我不确定你想在这里实现什么。我对 Scala 中的类型级编程没有任何经验,但这对我来说看起来不像是正确的类型级编程。你到底想用 in 中的类型参数来实现Y什么xToNextPage[Y](x : X)?的唯一可能值Next[X, Y]是,因为和Next[X, AnyRef]的最不常见的祖先是。摆脱给你唯一正确的答案:FooBarAnyRefY

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,但我认为这超出了类型系统的限制。

于 2013-09-02T16:04:17.737 回答