🎓 A1Learner
🔍
0 of 52 lessons completed

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
end

A 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
end

A 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
end

Key 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?