breandan
06/13/2017, 10:17 AMSequence
, but why isn't the operand of Sequence.plus(...)
evaluated lazily by default? Are there any plans to provide this behavior? Is there a way to use the stdlib functions to get a truly lazy implementation for concatenation of Iterables? @h0tk3yh0tk3y
06/13/2017, 10:56 AMSequence.plus(...)
, both left and right operands, I mean Sequence
instances, are evaluated before the plus
call (just like any function has its arguments evaluated before it is called). The items from the right operand sequence are evaluated only when the left one finishes, but still the Sequence
itself is created eagerly (and this is exactly what was preventing us from writing a recursive primes filter in the answer). As far as I can tell, now you can do what is done in the answer using Sequence { ... }
constructor from stdlib:
lazyRight = left + Sequence { createSomeIterator() }
In this case, what's inside the lambda is evaluated only when an item from the second sequence is queried.breandan
06/13/2017, 1:00 PMfun primesFilter(from: Sequence<Int>): Sequence<Int> = from.iterator().let {
val current = it.next()
sequenceOf(current) + Sequence {
primesFilter(it.asSequence().filter { it % current != 0 }).iterator()
}
}
I noticed that when benchmarking the two implementations, the Sequence {...}
constructor takes significantly longer than your lazyPlus {...}
implementation. Here's the full code:
fun primes(): Sequence<Int> {
fun primesFilter(from: Sequence<Int>): Sequence<Int> = from.iterator().let {
val current = it.next()
// h0tk3y's lazy concatenation: 588ms
sequenceOf(current) lazyPlus {
primesFilter(it.asSequence().filter { it % current != 0 })
}
// stdlib's lazy concatenation: 23923ms
// sequenceOf(current) + Sequence {
// primesFilter(it.asSequence().filter { it % current != 0 }).iterator()
// }
}
return primesFilter((2..Int.MAX_VALUE).asSequence())
}
fun main(args: Array<String>) {
println(measureTimeMillis { primes().take(2000).toList() })
}
Am I doing this correctly?h0tk3y
06/13/2017, 7:26 PM+ Sequence { ...iterator() }
solution could take longer because of the overhead Sequence { ... }
and .iterator()
introduce creating the objects, but I thought it shouldn't be that much.