Created
October 22, 2019 12:17
-
-
Save Castux/d68090ac16c13fbfd89caa185b432b8e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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