Невозможно переписать рекурсивный вызов: он не находится в хвостовой позиции - PullRequest
0 голосов
/ 30 апреля 2020

Я играл с Дотти и пытался реализовать простой Список. Вот как я это реализовал:

enum List[+A] {
  case Cons(head :A, tail: List[A])
  case Nil extends List[Nothing]
}

Проблема, с которой я столкнулся, заключается в том, что эта реализация не может быть скомпилирована с Cannot rewrite recursive call: it is not in tail position:

@tailrec
def drop[A](n: Int, as: List[A]): List[A] = 
  (n,as) match
    case (0, _) => as
    case (_, Nil) => Nil
    case (x, Cons(_, tail)) => drop(x-1, tail)

В другом файле, который я попробовал ту же реализацию со списком стандартной библиотеки, и он компилируется:

@tailrec
def drop[A](n: Int, as: List[A]): List[A] = 
  (n,as) match
    case (0, _) => as
    case (_, Nil) => Nil
    case (x, _ :: tail) => drop(x-1, tail)

Может быть, я просто устал и не вижу очевидной ошибки, но, может быть, здесь есть что-то еще? Любая странность, вызванная тем, что extends List[Nothing] я должен был добавить, чтобы код скомпилировался?

Спасибо!

РЕДАКТИРОВАТЬ :

1 Ответ

4 голосов
/ 30 апреля 2020

В Dotty 0.25.0-bin-20200429-c5a76f0-NIGHTLY

import scala.annotation.tailrec

enum List[+A] {
  case Cons(head :A, tail: List[A])
  case Nil extends List[Nothing]

  @tailrec
  def drop[A](n: Int, as: List[A]): List[A] =
    (n,as) match
      case (0, _) => as
      case (_, Nil) => Nil
      case (x, Cons(_, tail)) => drop(x-1, tail)
}

производит

TailRec optimisation not applicable, method drop is neither private nor final so can be overridden

Если вы сделаете drop final или private, код скомпилируется.

...