Lua Coroutines
Use when lua coroutines for cooperative multitasking including coroutine creation, yielding and resuming, passing values, generators, iterators, asynchronous patterns, state machines, and producer-consumer implementations.
What this skill does
# Lua Coroutines
## Introduction
Coroutines in Lua provide cooperative multitasking, enabling functions to
suspend and resume execution. Unlike threads, coroutines don't run in parallel
but yield control explicitly, making them simpler to reason about while enabling
powerful asynchronous patterns without callback complexity.
Coroutines are first-class values in Lua, created from functions and managed
through the coroutine library. They maintain their own stack, local variables,
and instruction pointer, allowing suspension at any point and resumption later.
This enables elegant implementations of generators, iterators, and state machines.
This skill covers coroutine basics, yielding and resuming with values, generators
and iterators, producer-consumer patterns, asynchronous I/O simulation, state
machines, error handling, and practical coroutine patterns.
## Coroutine Fundamentals
Coroutines enable functions to pause and resume execution, providing cooperative
multitasking without thread complexity.
```lua
-- Creating a coroutine
local function simple_task()
print("Task started")
coroutine.yield()
print("Task resumed")
coroutine.yield()
print("Task finished")
end
local co = coroutine.create(simple_task)
-- Checking coroutine status
print(coroutine.status(co)) -- "suspended"
-- Resuming coroutine
coroutine.resume(co) -- Prints "Task started"
print(coroutine.status(co)) -- "suspended"
coroutine.resume(co) -- Prints "Task resumed"
coroutine.resume(co) -- Prints "Task finished"
print(coroutine.status(co)) -- "dead"
-- Coroutine with parameters
local function greet(name)
print("Hello, " .. name)
local response = coroutine.yield("What's your age?")
print(name .. " is " .. response .. " years old")
end
local co2 = coroutine.create(greet)
local success, question = coroutine.resume(co2, "Alice")
print(question) -- "What's your age?"
coroutine.resume(co2, 30) -- "Alice is 30 years old"
-- Coroutine returning values
local function counter()
for i = 1, 5 do
coroutine.yield(i)
end
return "done"
end
local co3 = coroutine.create(counter)
repeat
local success, value = coroutine.resume(co3)
print(value)
until coroutine.status(co3) == "dead"
-- Coroutine wrap (simpler interface)
local function wrapped_task()
for i = 1, 3 do
coroutine.yield(i * 10)
end
end
local f = coroutine.wrap(wrapped_task)
print(f()) -- 10
print(f()) -- 20
print(f()) -- 30
-- Running coroutine
local function self_aware()
if coroutine.running() then
print("Running in coroutine")
else
print("Running in main")
end
end
self_aware() -- "Running in main"
coroutine.resume(coroutine.create(self_aware)) -- "Running in coroutine"
-- Yielding from nested calls
local function inner()
print("Inner start")
coroutine.yield("from inner")
print("Inner end")
end
local function outer()
print("Outer start")
inner()
print("Outer end")
end
local co4 = coroutine.create(outer)
coroutine.resume(co4) -- Prints "Outer start" and "Inner start"
coroutine.resume(co4) -- Prints "Inner end" and "Outer end"
-- Bidirectional communication
local function echo()
while true do
local value = coroutine.yield()
if value == nil then break end
print("Echo: " .. value)
end
end
local co5 = coroutine.create(echo)
coroutine.resume(co5)
coroutine.resume(co5, "Hello")
coroutine.resume(co5, "World")
coroutine.resume(co5) -- nil terminates
-- Error handling in coroutines
local function faulty()
print("Before error")
error("Something went wrong")
print("After error") -- Never executes
end
local co6 = coroutine.create(faulty)
local success, err = coroutine.resume(co6)
if not success then
print("Error caught: " .. err)
end
```
Coroutines enable cooperative multitasking where functions explicitly yield
control rather than being preempted.
## Generators and Iterators
Coroutines elegantly implement generators and custom iterators for lazy
evaluation and infinite sequences.
```lua
-- Simple generator
local function range(from, to, step)
step = step or 1
return coroutine.wrap(function()
for i = from, to, step do
coroutine.yield(i)
end
end)
end
for n in range(1, 10, 2) do
print(n) -- 1, 3, 5, 7, 9
end
-- Infinite generator
local function naturals()
return coroutine.wrap(function()
local n = 1
while true do
coroutine.yield(n)
n = n + 1
end
end)
end
local gen = naturals()
print(gen()) -- 1
print(gen()) -- 2
print(gen()) -- 3
-- Fibonacci generator
local function fibonacci()
return coroutine.wrap(function()
local a, b = 0, 1
while true do
coroutine.yield(a)
a, b = b, a + b
end
end)
end
local fib = fibonacci()
for i = 1, 10 do
print(fib())
end
-- Filter generator
local function filter(gen, predicate)
return coroutine.wrap(function()
for value in gen do
if predicate(value) then
coroutine.yield(value)
end
end
end)
end
local evens = filter(range(1, 20), function(n) return n % 2 == 0 end)
for n in evens do
print(n) -- 2, 4, 6, 8, 10, 12, 14, 16, 18, 20
end
-- Map generator
local function map(gen, transform)
return coroutine.wrap(function()
for value in gen do
coroutine.yield(transform(value))
end
end)
end
local squared = map(range(1, 5), function(n) return n * n end)
for n in squared do
print(n) -- 1, 4, 9, 16, 25
end
-- Take generator (limit results)
local function take(gen, n)
return coroutine.wrap(function()
local count = 0
for value in gen do
if count >= n then break end
coroutine.yield(value)
count = count + 1
end
end)
end
local first5 = take(naturals(), 5)
for n in first5 do
print(n) -- 1, 2, 3, 4, 5
end
-- Chain generators
local function chain(...)
local generators = {...}
return coroutine.wrap(function()
for _, gen in ipairs(generators) do
for value in gen do
coroutine.yield(value)
end
end
end)
end
local combined = chain(range(1, 3), range(10, 12))
for n in combined do
print(n) -- 1, 2, 3, 10, 11, 12
end
-- Zip generators
local function zip(gen1, gen2)
return coroutine.wrap(function()
while true do
local v1 = gen1()
local v2 = gen2()
if v1 == nil or v2 == nil then break end
coroutine.yield(v1, v2)
end
end)
end
local letters = coroutine.wrap(function()
for c in string.gmatch("abc", ".") do
coroutine.yield(c)
end
end)
local zipped = zip(range(1, 3), letters)
for num, letter in zipped do
print(num, letter) -- 1 a, 2 b, 3 c
end
-- Permutation generator
local function permute(array)
return coroutine.wrap(function()
local function perm(arr, n)
n = n or #arr
if n == 1 then
coroutine.yield(arr)
else
for i = 1, n do
arr[n], arr[i] = arr[i], arr[n]
perm(arr, n - 1)
arr[n], arr[i] = arr[i], arr[n]
end
end
end
local copy = {}
for i, v in ipairs(array) do
copy[i] = v
end
perm(copy)
end)
end
for perm in permute({1, 2, 3}) do
print(table.concat(perm, ", "))
end
-- File line iterator
local function lines(filename)
return coroutine.wrap(function()
local file = io.open(filename, "r")
if not file then return end
for line in file:lines() do
coroutine.yield(line)
end
file:close()
end)
end
```
Generators enable lazy evaluation and infinite sequences with clean, readable
syntax.
## Producer-Consumer Pattern
Coroutines elegantly implement producer-consumer patterns without explicit
queues or callbacks.
```lua
-- Basic producer-consumer
local function producer()
return coroutine.create(function()
for i = 1, 10 do
print("Producing " .. i)
coroutine.yield(i)
end
end)
end
local function consumer(prod)
while coroutine.status(prod) ~= "dead" do
local success, value = coroutine.resume(prod)
if success and value then
print("Consuming " .. value)
end
end
end
local prod = producer()
cRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.