Scala:类型注释使尾递归检查失败

时间:2015-06-25 19:17:54

标签: scala annotations tail-recursion type-erasure

我为这个模式匹配添加了类型注释,仅仅是为了我自己的理解。

@annotation.tailrec def run[A](io: IO[A]): A = {
  io match {
    case Return(a) => a
    case Suspend(r) => r()
    case FlatMap(x, f) => x match {
      case Return(a) => run(f(a))
      case Suspend(r) => run(f(r()))
      case FlatMap(y, g) => 
        run(y flatMap (a => g(a) flatMap f))
    }
  }
}

为什么这些类型的注释会破坏尾递归检查?添加了新的类型定义和类型注释后,我不会清楚地看到代价高昂的新递归。

could not optimize @tailrec annotated method run: it contains a recursive call not in tail position
io match {
^

@annotation.tailrec def run[A](io: IO[A]): A = {
  type rType = Unit => A
  type fType = A => IO[A]
  type gType = A => IO[A]
  io match {
    case Return(a: A) => a
    case Suspend(r: rType) => r()
    case FlatMap(x: IO[A], f: fType) => x match {
      case Return(a: A) => run(f(a))
      case Suspend(r: rType) => run(f(r()))
      case FlatMap(y: IO[A], g: gType) => 
        run(y flatMap (a => g(a) flatMap f))
    }
  }
}

与之匹配的案例类:

case class Return[A](a: A) extends IO[A]
case class Suspend[A](resume: () => A) extends IO[A]
case class FlatMap[A,B](sub: IO[A], k: A => IO[B]) extends IO[B]

只要省略了类型注释,就可以输入' a'在行

 F.flatMap(r)((a: A) => run(f(a)))

必须是'任何':

 [error]  found   : A => F[A]
 [error]  required: Any => F[A]
 [error]         F.flatMap(r)((a: A) => run(f(a)))

编译:

 F.flatMap(r)(a => run(f(a)))

奖金问题。

似乎不允许与case类中的函数进行模式匹配,如下所示:

io match {
  ...
  case Suspend(r: Unit => A) => r()
  /* or */
  case Suspend(r: () => A) => r()
  ...
}

编译:

io match {
  ...
  case Suspend(r: Function0[A]) => r()
  ...
}

为什么会这样?

由于类型擦除,这些类型的注释最终没有多大用处。在注释这些类型之后,我可以期待看到这样的编译器警告:

abstract type pattern ... is unchecked since it is eliminated by erasure

此代码来自第13章,或者包含fpinscala.iomonad," Scala中的函数编程。" https://github.com/fpinscala/fpinscala

由于

1 个答案:

答案 0 :(得分:1)

奖金回答: 关于类型擦除有很多问题,请看How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?你可以写一些像

这样的东西
    case FlatMap(y: IO[A], g: gType@unchecked) if g.isInstanceOf[gType] =>