Поддерживает ли Scala оптимизацию хвостовой рекурсии?

Поддерживает ли Scala оптимизацию хвостовой рекурсии?


person Roman Kagan    schedule 04.11.2009    source источник


Ответы (4)


Как сказано в других плакатах, Scala выполняет оптимизацию хвостовой рекурсии во время компиляции. То есть хвостовая рекурсивная функция преобразуется компилятором в цикл (вызов метода преобразуется в переход), что можно увидеть из трассировки стека при запуске хвостовой рекурсивной функции.

Попробуйте следующий фрагмент:

def boom(n: Int): Nothing = if(n<=0) throw new Exception else boom(n-1)
boom(10)

и проверьте трассировку стека. Он покажет только один вызов функциональной стрелы, поэтому скомпилированный байт-код не является рекурсивным.

Существует предложение реализовать хвостовые вызовы на уровне JVM, что, на мой взгляд, было бы здорово, поскольку тогда JVM могла бы выполнять оптимизацию времени выполнения, а не просто оптимизировать время компиляции кода - и, возможно, могло бы означать более гибкую хвостовую рекурсию. По сути, tailcall invoke будет вести себя точно так же, как обычный метод invoke, но сбросит стек вызывающего, когда это будет безопасно - в спецификации JVM указано, что кадры стека должны быть сохранены, поэтому JIT должен выполнить некоторый статический анализ кода, чтобы выяснить, не собираются ли никогда не использовать кадры стека.

Текущий статус - proto 80%. Я не думаю, что это будет сделано вовремя для Java 7 (invokedynamic имеет больший приоритет, и реализация почти завершена), но Java 8 может увидеть это реализованным.

person Flaviu Cipcigan    schedule 05.11.2009
comment
Текущее состояние прото 80%. Я не понимаю. Я думал, что Арнольд Швайгхофер полностью реализовал это под руководством Джона Роуза много лет назад? - person J D; 06.11.2010
comment
@JanHarrop, может быть, дело в хвостовой рекурсии, а не в общих хвостовых вызовах? - person Cubic; 13.11.2012
comment
@Cubic: Нет, это были общие хвосты. Арнольд также реализовал их в LLVM. - person J D; 13.03.2016

В Scala 2.8 вы можете использовать @tailrec для обозначения определенного метода, который, как вы ожидаете, оптимизирует компилятор:

import scala.annotation.tailrec

@tailrec def factorialAcc(acc: Int, n: Int): Int = {
  if (n <= 1) acc
  else factorialAcc(n * acc, n - 1)
}

Если метод не может быть оптимизирован, вы получите ошибку времени компиляции.

person Vitalii Fedorenko    schedule 05.03.2011
comment
Необходимо импортировать аннотацию с помощью import scala.annotation.tailrec - person Callum; 01.09.2011

Scala 2.7.x поддерживает оптимизацию хвостового вызова для саморекурсии (вызывающей себя функции) конечных методов и локальных функций.

Scala 2.8 также может иметь библиотечную поддержку для трамплина, который является методом оптимизации взаимно рекурсивных функций.

Много информации о состоянии рекурсии Scala можно найти в Блог Рича Догерти.

person Daniel C. Sobral    schedule 05.11.2009
comment
Также о монадических батутах: apocalisp.wordpress. ru / 2011/10/26 / - person Vadzim; 25.04.2013

Только в очень простых случаях, когда функция является саморекурсивной.

Подтверждение способности хвостовой рекурсии.

Однако похоже, что Scala 2.8 может улучшить распознавание хвостовой рекурсии.

person Stefan Kendall    schedule 04.11.2009
comment
Только в очень простых случаях, когда функция является саморекурсивной. Означает ли это, что при использовании продолжений легко может закончиться место в стеке? - person Giorgio; 15.02.2013