Skip to content

Instantly share code, notes, and snippets.

@Castux
Created October 22, 2019 12:17
Show Gist options
  • Save Castux/d68090ac16c13fbfd89caa185b432b8e to your computer and use it in GitHub Desktop.
Save Castux/d68090ac16c13fbfd89caa185b432b8e to your computer and use it in GitHub Desktop.
local enumerator = {}
function enumerator.new(fun)
return setmetatable({},
{
__index = enumerator,
__call = fun
})
end
function enumerator.from_yieldable(fun)
return enumerator.new(coroutine.wrap(fun))
end
function enumerator.from_list(l)
local i = 0
return enumerator.new(function()
i = i + 1
return l[i]
end)
end
function enumerator.to_list(enum)
local res = {}
local next = enum()
while next do
res[#res + 1] = next
next = enum()
end
return res
end
function enumerator.iterate(value, f)
local current
return enumerator.new(function()
current = current and f(current) or value
return current
end)
end
function enumerator.range(a,b,step)
local step = step or 1
return enumerator.iterate(a, function(x) return x + step end)
:take_while(function(x)
if step > 0 then
return x <= b
else
return x >= b
end
end)
end
function enumerator.single(v)
return enumerator.constant(v):take(1)
end
function enumerator.constant(v)
return enumerator.new(function()
return v
end)
end
function enumerator.take(enum, n)
local i = 1
return enumerator.new(function()
if i <= n then
i = i + 1
return enum()
end
end)
end
function enumerator.drop(enum, n)
local i = 1
return enumerator.new(function()
while i <= n do
i = i + 1
enum()
end
return enum()
end)
end
function enumerator.take_while(enum, f)
return enumerator.new(function()
local next = enum()
if next and f(next) then
return next
end
end)
end
function enumerator.drop_while(enum, f)
return enumerator.new(function()
local next = enum()
while next and f(next) do
next = enum()
end
return next
end)
end
function enumerator.nth(enum, n)
return enum:drop(n-1):take(1)
end
function enumerator.map(enum, f)
return enumerator.new(function()
local next = enum()
if next then
return f(next)
end
end)
end
function enumerator.filter(enum, f)
return enumerator.new(function()
while true do
local next = enum()
if not next then
break
end
if f(next) then
return next
end
end
end)
end
function enumerator.append(enum1, enum2)
return enumerator.from_yieldable(function()
for v in enum1 do
coroutine.yield(v)
end
for v in enum2 do
coroutine.yield(v)
end
end)
end
function enumerator.zip(enum1, enum2, f)
return enumerator.new(function()
local v1,v2 = enum1(),enum2()
if not (v1 and v2) then
return nil
end
return f(v1,v2)
end)
end
function enumerator.fold(enum, f)
local value
return enumerator.new(function()
local next = enum()
if not next then
return nil
end
if not value then
value = next
else
value = f(value,next)
end
return value
end)
end
local result = {1,1}
local test = enumerator.from_list(result)
:zip(enumerator.from_list(result):drop(1), function(a,b) return a + b end)
:map(function(v) table.insert(result, v); return v end)
:take(50)
for v in test do
print(v)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment