Это не ошибка, это не недосмотр и не хвостовая рекурсия.
Да, вы можете написать код в хвостовой рекурсивной манере, но этоне означает, что каждый эквивалентный алгоритм можно сделать хвостовым рекурсивным.Давайте возьмем этот код:
maybeNext.map{rec].getOrElse(n)
Во-первых, последний звонок - getOrElse(n)
.Этот вызов не является обязательным - он всегда выполняется, и необходимо скорректировать результат.Но давайте проигнорируем это.
Следующий за последним вызовом - map{rec}
. Не до rec
.На самом деле, rec
не называется вообще в вашем коде!Некоторая другая функция вызывает его (и, фактически, это не последний вызов map
), но не ваша функция.
Чтобы что-то было хвостовым рекурсивно, вам нужно иметь возможность заменитьзвонить с "гото", так сказать.Например:
def rec(n: Int): Int = {
BEGINNING:
val maybeNext = if (n >= 99) None else Some(n+1)
if (maybeNext.isEmpty) n
else {
n = maybeNext.get
goto BEGINNING
}
}
Как это могло бы произойти в другом коде?
def rec(n: Int): Int = {
BEGINNING:
val maybeNext = if (n >= 99) None else Some(n+1)
maybeNext.map{x => n = x; goto BEGINNING}.getOrElse(n)
}
Goto здесь не внутри rec
.Он находится внутри анонимного Function1
apply
, который, в свою очередь, находится внутри Option
map
, поэтому ветвь здесь будет оставлять два стековых фрейма при каждом вызове.Предполагая, что ветвление между методами было возможно в первую очередь.