9. Sequences
list.asSequence()
.filter { … }
.map { … }
.filter { … }
// 1, 2, 4, 8, //.
val seq = generateSequence(1) { it * 2 }
for (item in seq) {
println(item)
}
interface Sequence<out T> {
operator fun iterator(): Iterator<T>
}
interface Iterator<out T> {
operator fun next(): T
operator fun hasNext(): Boolean
}
val iter = seq.iterator()
while (iter.hasNext()) {
val item = iter.next()
println(item)
}
10. Sequence builders
val fib = sequence {
print("Start ")
yield(1)
// Label 1
var cur = 1
var next = 1
while (true) {
print("Next ")
yield(next)
// Label 2
val tmp = cur + next
cur = next
next = tmp
}
}
fib.take(4).forEach { print("$it ") }
// Start 1 Next 1 Next 2 Next 3
fun <T> sequence(
block: suspend SequenceScope<T>.() ?> Unit
): Sequence<T>
abstract class SequenceScope<in T> {
abstract suspend fun yield(value: T)
}
11. class SequenceBuilder<T> : SequenceScope<T>(), Iterator<T> {
var state: State = State.NotReady // enum NotReady, Ready, Done
var nextValue: T? = null
var nextStep: Continuation<Unit>? = null
override fun next(): T = when (state) {
…
}
override fun hasNext(): Boolean {
…
}
override suspend fun yield(value: T) {
…
}
}
12. class SequenceBuilder<T> : SequenceScope<T>(), Iterator<T> {
var state: State = State.NotReady // enum NotReady, Ready, Done
var nextValue: T? = null
var nextStep: Continuation<Unit>? = null
override fun next(): T = when (state) {
State.NotReady ?> if (hasNext()) next() else error("oops")
State.Ready ?> {
state = State.NotReady
nextValue as T
}
else ?> error("oops")
}
override fun hasNext(): Boolean {
…
}
override suspend fun yield(value: T) {
…
}
}
13. class SequenceBuilder<T> : SequenceScope<T>(), Iterator<T> {
var state: State = State.NotReady // enum NotReady, Ready, Done
var nextValue: T? = null
var nextStep: Continuation<Unit>? = null
override fun next(): T = when (state) {}
override fun hasNext(): Boolean {
while (true) {
when (state) {
State.NotReady ?> {
state = State.Done
nextStep?!.resume(Unit)
}
State.Done ?> return false
State.Ready ?> return true
}
}
}
override suspend fun yield(value: T) {
…
}
}
interface Continuation<in T> {
val context: CoroutineContext
fun resumeWith(result: Result<T>)
}
fun <T> Continuation<T>.resume(value: T) =
resumeWith(Result.success(value))
14. class SequenceBuilder<T> : SequenceScope<T>(), Iterator<T> {
var state: State = State.NotReady // enum NotReady, Ready, Done
var nextValue: T? = null
var nextStep: Continuation<Unit>? = null
override fun next(): T = when (state) {}
override fun hasNext(): Boolean {
while (true) {
when (state) {
State.NotReady ?> {
state = State.Done
nextStep?!.resume(Unit)
}
State.Done ?> return false
State.Ready ?> return true
}
}
}
override suspend fun yield(value: T) {
…
}
}
val fib = sequence {
print("Start ")
yield(1)
// Label 1
var cur = 1
var next = 1
while (true) {
print("Next ")
yield(next)
// Label 2
val tmp = cur + next
cur = next
next = tmp
}
}
15. class SequenceBuilder<T> : SequenceScope<T>(), Iterator<T> {
var state: State = State.NotReady // enum NotReady, Ready, Done
var nextValue: T? = null
var nextStep: Continuation<Unit>? = null
override fun hasNext(): Boolean {
…
}
override fun next(): T = when (state) {
…
}
override suspend fun yield(value: T) {
nextValue = value
state = State.Ready
}
}
val fib = sequence {
print("Start ")
yield(1)
// Label 1
var cur = 1
var next = 1
while (true) {
print("Next ")
yield(next)
// Label 2
val tmp = cur + next
cur = next
next = tmp
}
}
16. class SequenceBuilder<T> : SequenceScope<T>(), Iterator<T> {
var state: State = State.NotReady // enum NotReady, Ready, Done
var nextValue: T? = null
var nextStep: Continuation<Unit>? = null
override fun hasNext(): Boolean {
…
}
override fun next(): T = when (state) {
…
}
override suspend fun yield(value: T) {
nextValue = value
state = State.Ready
return suspendCoroutineUninterceptedOrReturn { c ->
nextStep = c
COROUTINE_SUSPENDED
}
}
}
val fib = sequence {
print("Start ")
yield(1)
// Label 1
var cur = 1
var next = 1
while (true) {
print("Next ")
yield(next)
// Label 2
val tmp = cur + next
cur = next
next = tmp
}
}
17. Continuation Passing Style
T | COROUTINE_SUSPENDED
suspend fun yield(value: T): Unit
source code
fun yield(value: T, cont: Continuation<Unit>): Any?
compiled code
18. Continuation Passing Style
override suspend fun yield(value: T) {
nextValue = value
state = State.Ready
return suspendCoroutineUninterceptedOrReturn { cont ->
nextStep = cont
COROUTINE_SUSPENDED
}
}
override suspend fun yield(value: T, cont: Continuation<Unit>): Any? {
nextValue = value
state = State.Ready
nextStep = cont
return COROUTINE_SUSPENDED
}
21. Deeply recursive functions
fun depth(t: Tree?): Int =
if (t ?= null) 0 else maxOf(depth(t.left), depth(t.right)) + 1
println(depth(deepTree)) // StackOverflowError
class Tree(val left: Tree? = null, val right: Tree? = null)
val deepTree = generateSequence(Tree()) { Tree(left = it) }.take(100_000).last()
val depth = DeepRecursiveFunction<Tree?, Int> { t ->
if (t ?= null) 0 else maxOf(
callRecursive(t.left),
callRecursive(t.right)
) + 1
}
println(depth(deepTree)) // Ok
22. Deeply recursive functions
sealed class DeepRecursiveScope<T, R> {
abstract suspend fun callRecursive(value: T): R
}
override suspend fun callRecursive(value: T): R {
return suspendCoroutineUninterceptedOrReturn { c ->
this.cont = c as Continuation<Any?>
this.value = value
COROUTINE_SUSPENDED
}
}
fun runCallLoop(): R {
while (true) {
val result = this.result
val cont = this.cont
?: return result.getOrThrow()
if (UNDEFINED_RESULT ?= result) {
val r = try {
function(this, value, cont)
} catch (e: Throwable) {
cont.resumeWithException(e)
continue
}
if (r ??= COROUTINE_SUSPENDED)
cont.resume(r as R)
} else {
this.result = UNDEFINED_RESULT
cont.resumeWith(result)
}
}
}
23. Deeply recursive functions
sealed class DeepRecursiveScope<T, R> {
abstract suspend fun callRecursive(value: T): R
}
override suspend fun callRecursive(value: T): R {
return suspendCoroutineUninterceptedOrReturn { c ->
this.cont = c as Continuation<Any?>
this.value = value
COROUTINE_SUSPENDED
}
}
fun runCallLoop(): R {
while (true) {
val result = this.result
val cont = this.cont
?: return result.getOrThrow()
if (UNDEFINED_RESULT ?= result) {
val r = try {
function(this, value, cont)
} catch (e: Throwable) {
cont.resumeWithException(e)
continue
}
if (r ??= COROUTINE_SUSPENDED)
cont.resume(r as R)
} else {
this.result = UNDEFINED_RESULT
cont.resumeWith(result)
}
}
}
26. Parsing expressions
sealed class Expr {
object TRUE : Expr()
object FALSE : Expr()
data class Var(val name: String) : Expr()
data class Not(val body: Expr) : Expr()
data class And(val left: Expr, val right: Expr) : Expr()
data class Or(val left: Expr, val right: Expr) : Expr()
data class Impl(val left: Expr, val right: Expr) : Expr()
}
val expr = "a & (b1 ?> c1) | a1 & !b | !(a1 ?> a2) ?> a"
27. object BooleanGrammar : Grammar<Expr>() {
init { register(regexToken("s+", ignored = true)) }
val tru by literalToken("true")
val fal by literalToken("false")
val id by regexToken("w+")
val lpar by literalToken("(")
val rpar by literalToken(")")
val not by literalToken("!")
val and by literalToken("&")
val or by literalToken("|")
val impl by literalToken("?>")
val negation by parser { -not * term() } map { Not(it) }
val braced by parser { -lpar * expr() * -rpar }
val term: Parser<Expr> by
(tru map TRUE) or (fal map FALSE) or (id map { Var(it.text) }) or negation or braced
val andChain by parser { leftAssociative(term, and) { a, _, b -> And(a, b) } }
val orChain by parser { leftAssociative(andChain, or) { a, _, b -> Or(a, b) } }
val implChain by parser { rightAssociative(orChain, impl) { a, _, b -> Impl(a, b) } }
val expr by implChain
override val root by expr
}
"a & (b1 ?> c1) | a1 & !b | !(a1 ?> a2) ?> a"
28. object BooleanGrammar : Grammar<Expr>() {
init { register(regexToken("s+", ignored = true)) }
val tru by literalToken("true")
val fal by literalToken("false")
val id by regexToken("w+")
val lpar by literalToken("(")
val rpar by literalToken(")")
val not by literalToken("!")
val and by literalToken("&")
val or by literalToken("|")
val impl by literalToken("?>")
val negation by parser { -not * term() } map { Not(it) }
val braced by parser { -lpar * expr() * -rpar }
val term: Parser<Expr> by
(tru map TRUE) or (fal map FALSE) or (id map { Var(it.text) }) or negation or braced
val andChain by parser { leftAssociative(term, and) { a, _, b -> And(a, b) } }
val orChain by parser { leftAssociative(andChain, or) { a, _, b -> Or(a, b) } }
val implChain by parser { rightAssociative(orChain, impl) { a, _, b -> Impl(a, b) } }
val expr by implChain
override val root by expr
}
29. suspend fun <T : Any, S : Any> ParsingScope.leftAssociative(
term: Parser<T>,
operator: Parser<S>,
transform: (T, S, T) ?> T
): T {
var l: T = term()
while (true) {
val (o, r) = maybe(parser { operator() to term() }) ?: break
l = transform(l, o, r)
}
return l
}
val input = "K | o | t | l | i | n | i | s | a | w | e | s | o | m | e"
parser { leftAssociative(id, "|") { l, _, r -> "$l$r" } }