Lua Chaining Iterators
A chaining iterator is an iterator adapter that takes another iterator and returns a new iterator with changed values or fewer values. Adapters compose, so one adapter can feed the next.
A map adapter changes each value
The map adapter doubles each value from the source. The loop prints the changed values.
local function up_to(limit)
local i = 0
return function()
i = i + 1
if i <= limit then
return i
end
return nil
end
end
local function map_values(source, fn)
return function()
local v = source()
if v == nil then
return nil
end
return fn(v)
end
end
local function double(x)
return x * 2
end
for v in map_values(up_to(3), double) do
print(v)
endA filter adapter keeps only matching values
The filter adapter asks its test for each value. Only even values reach the loop.
local function up_to(limit)
local i = 0
return function()
i = i + 1
if i <= limit then
return i
end
return nil
end
end
local function filter_values(source, test)
return function()
while true do
local v = source()
if v == nil then
return nil
end
if test(v) then
return v
end
end
end
end
local function is_even(x)
return x % 2 == 0
end
for v in filter_values(up_to(5), is_even) do
print(v)
endAdapters compose into a chain
The filter output feeds the map adapter. Even numbers are doubled, and odd numbers never reach the map.
local function up_to(limit)
local i = 0
return function()
i = i + 1
if i <= limit then
return i
end
return nil
end
end
local function map_values(source, fn)
return function()
local v = source()
if v == nil then
return nil
end
return fn(v)
end
end
local function filter_values(source, test)
return function()
while true do
local v = source()
if v == nil then
return nil
end
if test(v) then
return v
end
end
end
end
local function is_even(x)
return x % 2 == 0
end
local function double(x)
return x * 2
end
local chained = map_values(filter_values(up_to(6), is_even), double)
for v in chained do
print(v)
endExample
local function up_to(limit)
local i = 0
return function()
i = i + 1
if i <= limit then
return i
end
return nil
end
end
local function map_values(source, fn)
return function()
local v = source()
if v == nil then
return nil
end
return fn(v)
end
end
local function filter_values(source, test)
return function()
while true do
local v = source()
if v == nil then
return nil
end
if test(v) then
return v
end
end
end
end
local function is_even(x)
return x % 2 == 0
end
local function square(x)
return x * x
end
local chained = map_values(filter_values(up_to(8), is_even), square)
for v in chained do
print(v)
endKey points
- Adapter: a function that wraps an iterator and changes what it returns.
- Map adapter: an adapter that changes each value before it is returned.
- Filter adapter: an adapter that skips values that fail a test and returns only the rest.
- Composition: feeding the output of one adapter into another adapter builds a longer chain.
- One value at a time: each call to a chained iterator pulls only the next value through the chain.
In this example, the source counts from 1 to 8, the filter keeps only even values, and the map squares each kept value. The chain is built by feeding the filter output into the map adapter. The loop prints 4, 16, 36, and 64.
Note
a chain stays an iterator, so it works in a plain for loop with no extra step.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
You chain a filter for even numbers and then a map that doubles, over 1 to 5. What does the loop print?