Try to imagine what is going on here and what you ask the compiler. Approximate call optimization, approximately, turns a method call into a loop, taking method arguments and turning them into variables that are reassigned at each iteration of the loop.
There are two such "loop variables" here: n and the list box itself on which the get method is called, which is actually this in the body of the method. The following value for n excellent: it is n - 1 , as well as Int . However, the following value for the tail list cell is a problem: this is of type Cons[T] , but tail is of type List[T] .
Thus, the compiler cannot turn it into a loop, since there is no guarantee that tail is Cons[T] - and, of course, at the end of the list it is Nil .
One way to "fix":
case class Cons[T](val head: T, val tail: List[T]) extends List[T] { def isEmpty = false @tailrec final def get(n: Int) = n match { case 0 => head case _ => tail match { case c @ Cons(_, _) => c.get(n - 1) case nil @ Nil() => nil.get(n - 1) } } }
(It works if both Cons and Nil are case classes, but you probably want to make Nil a case object and List[T] covariant in T )
source share