【问题标题】:Why this Scala code hangs if you specify type-parameter?如果您指定类型参数,为什么这个 Scala 代码会挂起?
【发布时间】:2013-09-02 15:36:14
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    原因是它处于无限递归中,这要归功于隐式转换。从xToNextPage 中删除implicit 关键字并显示错误:

    <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]
    

    【讨论】:

      【解决方案2】:

      我不确定您要在这里实现什么。我对 Scala 中的类型级编程没有任何经验,但这对我来说看起来不像是正确的类型级编程。你到底想用xToNextPage[Y](x : X) 中的类型参数Y 来实现什么? 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 的解决方案,但我认为这超出了类型系统的限制。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-16
        • 2016-06-04
        • 2018-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-06
        • 1970-01-01
        相关资源
        最近更新 更多