Kotlin yield example

62 views Asked by At

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

There are 2 answers

1
Sweeper On BEST ANSWER

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.

0
ArekBulski On

As @Sweeper suggested:

fun Sequence<Int>.product(): Int {
    return this.reduce({ acc,x -> acc*x })
}

infix fun Int.powerof(exponent: Int): Int {
    return (1..exponent).asSequence().map({ this }).product()
}

fun main() {
    println(2 powerof 10)
}