¿Cómo lograr una function pura con progtwigción dinámica en Kotlin?

He intentado transformar parte de mi código en funciones puras para aprender a usar Kotlin de una manera funcional, con este simple fragment de código no puedo pensar en ninguna forma de hacer que mi function de calculateFibonacci Fibonacci sea una function pura.

Estoy al tanto de una solución potencialmente recursiva, pero ¿qué pasa con un posible desbordamiento de la stack? ¿Implementa Kotlin la optimization de la llamada de queue?

Ejemplo:

  val fibonacciValues = hashMapOf<Int, BigInteger>(0 to BigInteger.ONE, 1 to BigInteger.ONE); // * TODO investigate how to do dynamic programming with a pure function ** // private fun calculateFibonacci(n: Int): BigInteger? { if (fibonacciValues.contains(n)) { return fibonacciValues.get(n) } else { val f = calculateFibonacci(n - 2)!!.add(calculateFibonacci(n - 1)) fibonacciValues.put(n, f) return f } } 

Para el fragment completo, cargué esta idea: https://gist.github.com/moxi/e30f8e693bf044e8b6b80f8c05d4ac12

Todo se trata de salir del enfoque imperativo y pensar en términos de manipulación de secuencias.

En el caso de la secuencia de Fibonacci, podría ser complicado porque es muy tentador pensar en ello como una secuencia de Ints, pero se vuelve mucho más fácil si lo consideras como una secuencia de pares (de la cual derivarás una secuencia de Ints). )

Entonces, podrías crear una secuencia infinita de pares donde el siguiente par se define como el segundo elemento del par anterior y una sum de elementos en un par anterior:

 generateSequence(1 to 1) { it.second to it.first + it.second } .map { it.first } 

Y sí, puede utilizar la optimization de llamadas de queue marcando su método con la palabra key tailrec , sin preocupaciones sobre el desbordamiento de la stack. Usted simplemente lo aplica antes de la palabra key fun :

 fun fibonacciAt(n: Int) = { tailrec fun fibonacciAcc(n: Int, a: Long, b: Long): Long { return when (n == 0) { true -> b false -> fibonacciAcc(n - 1, a + b, a) } } fibonacciAcc(n, 1, 0) } 

Aquí hay más información sobre la Recursión de queue en Kotlin.

De cosecha propia:

 fun fib(i: Int): Int { tailrec fun go(k: Int, p: Int, c: Int): Int { return if (k == 0) p else go(k - 1, c, p + c) } return go(i, 0, 1) } 

generateSequence en realidad muestra una implementación de Fibonacci como ejemplo.

 fun fibonacci(): Sequence<Int> { // fibonacci terms // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, ... return generateSequence(Pair(0, 1), { Pair(it.second, it.first + it.second) }).map { it.first } } println(fibonacci().take(10).toList()) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 

Kotlin implementa la optimization de llamadas de queue

Sí, hay palabra key tailrec para eso.