Reputation: 79
I'm baffled by the generateSequence
in Kotlin. I seem to be reading the manual all wrong:
This is the function signature (for generateSequence
with seed):
fun <T : Any> generateSequence(
seed: T?,
nextFunction: (T) -> T?
): Sequence<T>
So the Sequence
should be of the same type of the seed and so should the next value going to the next iteration generation....
But the example in the man is:
fun fibonacci(): Sequence<Int> {
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]
So it would seem that the type of the Sequence
is Int
the seed is Pair<Int, Int>
.
The generator function maps Pair<Int, Int>
TO Int
.
How is the next value sent to the generator constructed where is the next Pair<Int, Int>
constructed (the output of the generator is Int
...)?
And how on earth does the function know when to stop? The generator never returns null
Upvotes: 4
Views: 5522
Reputation: 54204
So it would seem that the type of the Sequence is Int the seed is Pair.
The given fibonacci()
function uses generateSequence()
to generate a sequence of Pair
, and then uses the map
function to convert that sequence to a sequence of Int
.
val pairs = generateSequence(Pair(0, 1), { Pair(it.second, it.first + it.second) })
// (0,1), (1,1), (1,2), (2,3), (3,5), (5,8) ...
val ints = pairs.map { it.first }
// 0, 1, 1, 2, 3, 5
If it helps you think about it, you can imagine that the "entire" first sequence is generated before any pairs are converted to ints.
And how on earth does the function know when to stop?
It doesn't. But the example uses the take()
function to truncate the sequence to the first 10 items, and then prints that instead of printing an infinite sequence.
The sequence is lazy
; it only generates values (by calling the given generator function) when needed. So when generateSequence()
returns, it hasn't generated anything yet -- just created a sequence that can do so. Similarly, when applied to a sequence, the map()
call doesn't immediately map any values, just returns an amended sequence that will do so if/when any values get generated. It's only when take()
is called that the sequence will generate (and map) some values; and because the take() stops after 10 items, it won't get around to generating any more than that.
Upvotes: 8