Lua Coroutine Pipelines
A coroutine pipeline is a chain of stages where each stage passes its output to the next stage. Each stage is a coroutine that yields values to the stage after it.
A filter stage passes only even numbers
The source yields 1 through 4. The filter yields only the even values to the sink loop.
local source = coroutine.create(function()
for i = 1, 4 do
coroutine.yield(i)
end
end)
local filter = coroutine.create(function()
while true do
local ok, value = coroutine.resume(source)
if value == nil then
break
end
if value % 2 == 0 then
coroutine.yield(value)
end
end
end)
while coroutine.status(filter) ~= "dead" do
local ok, value = coroutine.resume(filter)
if value then
print(value)
end
endA map stage changes every value it pulls
The source yields 1 through 3. The map stage yields ten times each value it pulls.
local source = coroutine.create(function()
for i = 1, 3 do
coroutine.yield(i)
end
end)
local map = coroutine.create(function()
while true do
local ok, value = coroutine.resume(source)
if value == nil then
break
end
coroutine.yield(value * 10)
end
end)
while coroutine.status(map) ~= "dead" do
local ok, value = coroutine.resume(map)
if value then
print(value)
end
endA sink can add up the values it pulls
The source yields 1 through 5 and the filter passes only odd values. The sink adds those values and prints the total.
local source = coroutine.create(function()
for i = 1, 5 do
coroutine.yield(i)
end
end)
local filter = coroutine.create(function()
while true do
local ok, value = coroutine.resume(source)
if value == nil then
break
end
if value % 2 == 1 then
coroutine.yield(value)
end
end
end)
local total = 0
while coroutine.status(filter) ~= "dead" do
local ok, value = coroutine.resume(filter)
if value then
total = total + value
end
end
print(total)Example
local source = coroutine.create(function()
for i = 1, 6 do
coroutine.yield(i)
end
end)
local filter = coroutine.create(function()
while true do
local ok, value = coroutine.resume(source)
if value == nil then
break
end
if value % 2 == 0 then
coroutine.yield(value)
end
end
end)
local map = coroutine.create(function()
while true do
local ok, value = coroutine.resume(filter)
if value == nil then
break
end
coroutine.yield(value * value)
end
end)
while coroutine.status(map) ~= "dead" do
local ok, value = coroutine.resume(map)
if value then
print(value)
end
endKey points
- Stage: a stage is one coroutine that takes a value, changes it, and yields the result.
- Source: the source is the first stage that makes the first values.
- Filter: a filter stage passes on only the values that meet its rule.
- Sink: the sink is the last stage that takes values and uses them.
- Pull: a stage resumes the stage before it to pull the next value.
In this example, the source yields 1 through 6 and the filter passes only the even numbers. The map stage squares each even number it pulls. The sink prints 4, 16, and 36 in order.
Note
a stage ends when the stage before it yields nothing more.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A middle stage needs the next value from the stage before it. What does it do?