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)
}
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.