I have a function generating values. It does so by recursively calling itself, and whenever the base case is reached, a value is emitted. This is just a toy example, the real one is much more complicated, and thus harder to transform to something non-recursive.
I would like to do this as a sequence. But doing this won't compile on the line I yield, with the message
Suspension functions can be called only within coroutine body
Here's the attempt:
fun test1() = sequence {
fun a(i: Int) {
if (i > 4) {
yield(i) // <- fails to compile
} else {
a(i + 1)
a(i + 2)
a(i + 3)
}
}
a(1)
}
If I try to add the suspend keyword to function a, I instead get the error
Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope
I can make it work, by instead returning all the values and doing a yieldAll. The problem with this, however, is that it needs to do the whole computation and hold all the results in memory before the sequence can be used. For my case, this won't work as I'd run out of memory, or may even have an almost infinite amount of results where I only want to take a few.
So this works, but is not optimal
fun test2() = sequence {
fun a(i: Int): List<Int> {
if (i > 4) {
return listOf(i)
} else {
return listOf(
a(i + 1),
a(i + 2),
a(i + 3)
).flatten()
}
}
yieldAll(a(1))
}
Any ideas on how to combine sequences with a recursive function, allowing me to yield values without pre-computing and allocating memory for all of them?