kotlinsequenceyielditerable

Kotlin yield example


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.