Как я могу аннотировать эту хвостовую рекурсивную функцию Scala - PullRequest
2 голосов
/ 15 марта 2012

У меня есть функция, которую я знаю, это хвостовая рекурсия.Но из-за того, как я это определяю, компилятор жалуется на то, что функция имеет рекурсивный вызов в неконечной позиции.Это функция.

@tailrec
def travel: (Int, List[Char]) => Int = {
    case (n,        Nil) => n
    case (n, '~' :: sls) => travel(0, sls)
    case (n, '^' :: sls) => travel(max(n-1,0), sls)
    case (n, '>' :: sls) => travel(n+1, sls)
    case (_,  s  :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'")
}

Я получаю

error: could not optimize @tailrec annotated method travel: it contains a recursive call not in tail position
def travel: (Int, List[Char]) => Int = {

Если я напишу это так, она отлично работает.

@tailrec
def travel(n:Int, l:List[Char]): Int = (n,l) match {
    case (n,        Nil) => n
    case (n, '~' :: sls) => travel(0, sls)
    case (n, '^' :: sls) => travel(max(n-1,0), sls)
    case (n, '>' :: sls) => travel(n+1, sls)
    case (_,  s  :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'")
}

Я думаю, что-то естьделать со стилем объявления типа def: (Input) => Output = {}.Я использую его, потому что он выглядит чище, чем запись вложенных совпадений или совпадений в кортеже.

1 Ответ

7 голосов
/ 15 марта 2012

Два не совпадают. В первом случае метод создает функцию , которая затем вызывает метод снова (которая создает функцию и т. Д.). То есть вы создаете новый экземпляр Function1[(Int, List[Char]), Int] каждый раз, когда вызываете travel в первом случае. Неудивительно, что это не может быть преобразовано в инструкцию перехода. (Теоретически можно, но анализ будет довольно сложным, поскольку придется отказаться от создания всех этих объектов.)

Во втором случае это просто вызывающий метод, который можно преобразовать в переход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...