Corrotinas e Geradores
Nesta página
A corrotina é a pedra fundamental da concorrência em Zolo. Com
coroutine.create, coroutine.resume e coroutine.yield você pode suspender
e retomar funções arbitrariamente — sem OS threads, sem travamentos de dados.
O ciclo de vida é simples: suspended → running → suspended (a cada
yield) → dead (quando o corpo retorna).
Criação, resume com e sem argumentos, e consulta de status com coroutine.status.
// Feature: Coroutines (create / resume / yield)
// Syntax: `coroutine.create(fn)`, `coroutine.resume(co)`, `coroutine.yield(v)`
// When to use: lightweight state machines, pause and resume work,
// pull-based pipelines, simulating threads without OS threads.
//
// A coroutine is a suspended function. Calling `resume` runs it
// until the next `yield` (or return). Each `yield` "pushes"
// a value back to whoever called `resume`.
use std::coroutine
// Simple coroutine — produces three values and ends.
let co = coroutine.create(|| {
coroutine.yield("first")
coroutine.yield("second")
coroutine.yield("third")
})
print(coroutine.resume(co)) // first
print(coroutine.resume(co)) // second
print(coroutine.resume(co)) // third
print(coroutine.status(co)) // dead
// Coroutine with arguments — `resume` passes, `yield` returns.
let echo = coroutine.create(|x: int| {
var n = x
while n > 0 {
coroutine.yield(n)
n = n - 1
}
})
print(coroutine.resume(echo, 3)) // 3
print(coroutine.resume(echo)) // 2
print(coroutine.resume(echo)) // 1
// Status: "suspended" before the first resume, "dead" after it returns.
let lazy = coroutine.create(|| {
coroutine.yield(42)
})
print(coroutine.status(lazy)) // suspended
coroutine.resume(lazy)
print(coroutine.status(lazy)) // suspended (still has a pending yield)
coroutine.resume(lazy) // finishes the body
print(coroutine.status(lazy)) // dead
Geradores (fn*) são uma camada de açúcar sobre corrotinas voltada para
sequências lazy. A função retorna um handle que, ao ser chamado, avança até o
próximo yield. Quando o corpo termina, retorna nil.
Isso permite sequências infinitas: o trabalho só acontece quando o chamador pede o próximo valor.
Gerador finito, Fibonacci infinito, gerador de strings e pipeline gerador+filtro.
// Feature: Generators (`fn*`) with yield
// Syntax: `fn* name(params) { yield expr }`
// When to use: lazy/infinite sequences, streams, pipelines where
// we do not want to materialize everything in memory.
//
// A generator is a function that produces values on demand. Each
// call to the returned handle advances to the next `yield`. When
// the function ends, it returns `nil`.
// Finite generator.
fn* counter(limit: int) {
var i = 0
while i < limit {
yield i
i += 1
}
}
let gen = counter(4)
print(gen()) // 0
print(gen()) // 1
print(gen()) // 2
print(gen()) // 3
print(gen()) // nil (exhausted)
// INFINITE generator — possible because it is lazy.
fn* fibonacci() {
var a = 0
var b = 1
loop {
yield a
let temp = a + b
a = b
b = temp
}
}
let fib = fibonacci()
for i in 0..8 {
print("fib({i}) = {fib()}")
}
// expected: fib(0) = 0 ... fib(7) = 13
// String generator — any type works.
fn* statuses() {
yield "loading"
yield "ready"
yield "done"
}
let st = statuses()
var s = st()
while s != nil {
print("status: {s}")
s = st()
}
// Pipeline: generator + filter.
fn* range_step(start: int, stop: int, step: int) {
var i = start
while i < stop {
yield i
i += step
}
}
let evens = range_step(0, 10, 2)
var v = evens()
while v != nil {
print("even: {v}")
v = evens()
}
Desafio
Escreva um gerador fn* primes() que produza números primos indefinidamente.
Use um take manual para imprimir os primeiros 10.
Veja também