I am learning Kotlin and for the love of it, I cannot get the yield/sequence straight. Could someone please correct my code?
fun Sequence<Int>.mapIterable(transform: (Int)->Int) = sequence {
this.forEach({ x -> yield(transform(x)) })
}
fun Sequence<Int>.product(): Int {
return this.reduce({ acc,x -> acc*x })
}
infix fun Int.powerof(exponent: Int): Int {
return (1..exponent).mapIterable({ x -> this }).product()
}
fun main() {
println(2 powerof 10)
}
>Solution :
mapIterable doesn’t compile because this is referring to the receiver of the sequence { ... } lambda, which is a SequenceScope<Int>. This SequenceScope is what allows you to call yield. What you meant is the receiver of mapIterable, which you can write as this@mapIterable.
Note that mapIterable is just reinventing Sequence.map. Just use map instead.
product is fine, but using reduce means that this throws an exception when the sequence is empty. I would write this with fold:
fun Sequence<Int>.product() = fold(1, Int::times)
In powerOf, (1..exponent) is not a Sequence<Int>, but an IntRange. You can convert it to a Sequence<Int> using asSequence:
(1..exponent).asSequence().map { x -> this }.product()
An alternative way is generateSequence to generate an infinite sequence of this, and then take(exponent).
infix fun Int.powerOf(exponent: Int) =
generateSequence { this }.take(exponent).product()
That said, doing things lazily here isn’t really much better than just creating a IntArray(exponent) { this }. The highest exponent you can meaningfully compute with this method is 31 (2^31 and you already reached the max value of Int). 31 integers in an array isn’t that much.