Saltar al contenido

Corrutinas y Generadores

En esta página

La corrutina es la piedra fundamental de la concurrencia en Zolo. Con coroutine.create, coroutine.resume y coroutine.yield puedes suspender y reanudar funciones arbitrariamente — sin hilos del SO, sin bloqueos de datos.

El ciclo de vida es simple: suspendedrunningsuspended (en cada yield) → dead (cuando el cuerpo retorna).

Creación, resume con y sin argumentos, y consulta de estado con coroutine.status.

01-coroutines-basic.zolo
Playground
// 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

Los generadores (fn*) son una capa de azúcar sobre corrutinas orientada a secuencias lazy. La función devuelve un handle que, al ser llamado, avanza hasta el siguiente yield. Cuando el cuerpo termina, devuelve nil.

Esto permite secuencias infinitas: el trabajo solo ocurre cuando el llamador pide el siguiente valor.

Generador finito, Fibonacci infinito, generador de cadenas y pipeline generador+filtro.

02-generators.zolo
Playground
// 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()
}

Desafío

Escribe un generador fn* primes() que produzca números primos indefinidamente. Usa un take manual para imprimir los primeros 10.

Buscar en Zolo

9 resultados

enespt-br