Leyendo sobre estructuras infinitas en Haskell, me puse a pensar en las secuencias en Kotlin. La biblioteca estándar de Kotlin contiene un tipo de contenedor: secuencias (Sequence <T>). Las secuencias ofrecen las mismas funciones que Iterable pero implementan otro enfoque un enfoque perezoso.
Cuando el procesamiento de un Iterable incluye varios pasos, se ejecutan de forma ansiosa o eager : cada paso de procesamiento completa y devuelve su resultado: una colección intermedia. El siguiente paso se ejecuta en esta colección. Pero, el procesamiento de múltiples pasos de secuencias se ejecuta de manera perezosa cuando es posible: la computación real ocurre solo cuando se solicita el resultado de toda la cadena de procesamiento.
El orden de ejecución de las operaciones también es diferente: la secuencia realiza todos los pasos de procesamiento uno por uno para cada elemento. Pero, Iterable completa cada paso para toda la colección y luego pasa al siguiente paso.
Por lo tanto, las secuencias nos permiten evitar generar resultados de pasos intermedios, mejorando así el rendimiento de toda la cadena de procesamiento de la colección. Sin embargo, la naturaleza perezosa de las secuencias agrega algunos gastos generales que pueden ser significativos al procesar colecciones más pequeñas o al realizar cálculos más simples. Por lo tanto, debe considerar tanto Sequence como Iterable y decidir cuál es mejor para cada caso.
Para crear una secuencia, llammamos a la función sequenceOf () que enumera los elementos como sus argumentos.
val nroSecuencia = sequenceOf ("cuatro", "tres", "dos", "uno")
Si ya tiene un objeto Iterable (como una Lista o un Conjunto), puede crear una secuencia a partir de él llamando a asSequence ().
val numeros = listOf ("uno", "dos", "tres", "cuatro")
val numbersSequence = numeros.asSequence()
Una forma más de crear una secuencia es construyéndola con una función que calcula sus elementos. Para construir una secuencia basada en una función, llame a generateSequence () con esta función como argumento. Opcionalmente, puede especificar el primer elemento como un valor explícito o como resultado de una llamada de función. La generación de la secuencia se detiene cuando la función proporcionada devuelve un valor nulo. Por lo tanto, la secuencia del siguiente ejemplo es infinita:
val oddNumbers = generateSequence(1) { it + 2 } // `it` is the previous element
println(oddNumbers.take(5).toList())
//println(oddNumbers.count()) // error: the sequence is infinite
Para crear una secuencia finita con generateSequence(), proporcione una función que devuelva nulo después del último elemento que necesita.
val oddNumbersLessThan10 = generateSequence(1) { if (it + 2 < 10) it + 2 else null }
println(oddNumbersLessThan10.count())
Finalmente, hay una función que le permite producir elementos de secuencia uno por uno o por trozos de tamaños arbitrarios: la función secuencia (). Esta función toma una expresión lambda que contiene llamadas de las funciones yield () y yieldAll (). Devuelven un elemento al consumidor de secuencia y suspenden la ejecución de secuencia () hasta que el consumidor solicite el siguiente elemento. yield () toma un solo elemento como argumento; yieldAll () puede tomar un objeto Iterable, un Iterador u otra Secuencia. Un argumento Sequence de yieldAll () puede ser infinito. Sin embargo, dicha llamada debe ser la última: todas las llamadas posteriores nunca se ejecutarán.
Veamos un ejemplo:
val oddNumbers = secuencia {
yield (1)
yieldAll (listaDe (3, 5))
yieldAll (generateSequence (7) {it + 2})
}
println (OddNumbers.take (5) .toList ())
Veamos la secuencia de fibonacci :
fun fibonacci(): Sequence<Int> = sequence {
var fibo = Pair(0, 1)
while (true) {
yield(fibo.first)
fibo = Pair(fibo.second, fibo.first + fibo.second)
}
}
fun main(args: Array<String>) {
fibonacci().take(4).toList().toString() eq "[0, 1, 1, 2]"
fibonacci().take(10).toList().toString() eq "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]"
}
Dejo link : https://kotlinlang.org/docs/reference/sequences.html