Scala: type annotations make tail recursion check fail

I am adding type annotations to this matching pattern just for my own understanding.

@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))
    }
  }
}

      

Why do these type annotations break tail recursion checking? When adding new type declarations and type annotations, I don't see a clear new recursion.

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))
    }
  }
}

      

Matching case classes:

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]

      

While type annotations are omitted, type 'a' on string

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

      

should be "Any":

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

      

This compiles:

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

      


Bonus question.

It seems that pattern matching with a function inside a case class like this is not allowed:

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

      

This compiles:

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

      

Why is this?


These type annotations will not be largely used at the end due to type erasure. After annotating these types, I can expect to see a compiler warning like this:

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

      


This code is from Chapter 13 or the fpinscala.iomonad package, "Functional Programming in Scala". https://github.com/fpinscala/fpinscala

thank

0


source to share


1 answer


Bonus answer: There are many questions about style erasure, take a look at How to get around style erasure in Scala? Or why can't I get the type parameter of my collections? You can write something like



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

      

+1


source







All Articles