Modul:Iterateurs
Belgekirina modulê[biafirîne]
--[[
---------------------------------------------------------------------------------
-- Iterating primitives
---------------------------------------------------------------------------------
Base functions to work on stateful lua iterators.
Function that creates iterators, like "pair" and "ipair", but stateful unlike them
-- May be building a duplicate of https://www.wikidata.org/wiki/Module:Luafun
--]]
local p = {}
----------------------------------------
-- Copied From Luafun
local methods = {} -- collects the methods to append to an iterator object
local register_method = (function(module, methods)
return function(name, func)
module[name] = func
methods[name] = func
end
end)(p, methods)
-- the metatable for an iterator object
local iterator_mt = {
-- usually called by for-in loop
__call = function(self, param, state)
return self.gen(param, state)
end;
__tostring = function(self)
return '<generator>'
end;
-- add all exported methods
__index = methods;
}
-- used to change an iterator function to an iterator objects to allow to attach methods to an iterator
local wrap = function(gen, param, state)
return setmetatable({
gen = gen,
param = param,
state = state
}, iterator_mt), param, state
end
p.wrap = wrap
local method0 = function(fun)
return function(self)
return fun(self.gen, self.param, self.state)
end
end
local methodn = function(fun)
return function(self, ...)
return fun(self.gen, ...)
end
end
--------------------------------------------------------
-- iterator constructor. Transforms an iterator over a sequence of values in
-- an iterator on the result of the "value_constructor" function applied to the initial values
-- (a kind of an equivalent of the functional "map" function that works on iterator instead of list)
-- this iterator works on values and ignore the keys
local function map(it, transformation)
assert(it, "map : no iterator provided")
return wrap(
function()
local val = it()
if val then return transformation(val) end
end
)
end
register_method("map", map)
-- like "map" except it works on pairs of values (usually key/val pairs)
-- this iterator works on pairs
local function pair_map(it, transformation)
assert(it, "pair_map : no iterator provided")
return wrap(
function()
local i, val = it()
if i then return transformation(i, val) end
end
)
end
register_method("pair_map",pair_map)
-- iterates on the values of another iterators and yield only the values that pass the criteria
-- (a kind of an equivalent of the functional "filter" function that works on iterator instead of list)
-- this iterator works on values
local function filter(it, criteria)
assert(it, "filter : no iterator provided")
assert(type(criteria)=="function", "no criteria provided")
return wrap(
function()
local val = it()
while val and not(criteria(val)) do
val = it()
end
return val
end
)
end
register_method("filter", filter)
-- pair version of the previous function
--this iterators works on pairs
local function pair_filter(it, criteria)
assert(it, "pair_filter : no iterator provided")
return wrap(
function()
local i, val = it()
while val and not(criteria(i, val)) do
i, val = it()
end
return i, val
end
)
end
register_method("pair_filter", pair_filter)
--creates a value only iterator from a "pair" one, yielding only the "keys" (first item of the pair)
--this iterators works on pairs
local function select_keys(it)
assert(it, "select_keys : no iterator provided")
return wrap(
function()
local i, val = it()
return i
end
)
end
register_method("select_keys", select_keys)
--creates a value only iterator from a "pair" one, yielding only the "values" (second item of the pair)
--this iterators works on pairs
local function select_vals(it)
assert(it, "pair_vals : no iterator provided")
return wrap(
function()
local i, val = it()
return val
end
)
end
p.select_vals = select_vals
-- create a stateful iterators that iterates on the values of a table
-- (from the stateless standard "pairs" iterator on tables)
local function on_vals(tabl)
local _f, _s, _v = pairs(tabl)
return wrap(
function()
if _s then
local i, res = _f(_s, _v)
_v = i
if not res then _s = nil end
return res
end
end
)
end
p.on_vals = on_vals
-- create a stateful iterators that iterates over the keys of a table
-- (from the stateless standard "pairs" iterator on tables)
local function on_pairs(tabl)
local _f, _s, _v = pairs(tabl)
return --wrap(
function()
if _s then
local i, res = _f(_s, _v)
_v = i
if not res then _s = nil end
return i, res
end
end
--)
end
p.on_pairs = on_pairs
-- equivalent of the "join" operation, with join({{"a"},{},{"b","c"}}) = {"a","b","c"}
-- for iterators.
-- if the parameter "it" is an iterator that yields {"a"} ; then {} ; then {"b","c"}
-- and "creator" is a function that creates an iterator that yields "b" then "c" from the table {"b","c"}
-- the "flatten"-ing of this parameter will yield "a" then "b" then "c"
local function flatten(it, creator)
assert(it, "flatten : no iterator provided")
assert(creator, "flatten : no iterator creator provided")
local main_val = it()
if main_val then
local sub_it = creator(main_val)
return wrap(
function()
if main_val then
local val = nil
while not val and main_val do
if sub_it then
val = sub_it()
end
if not val then
main_val = it()
if not main_val then return end
sub_it = creator(main_val)
end
end
return val
end
end
)
else
return wrap(function () return nil end)
end
end
register_method("flatten", flatten)
-- equivalent of list concatenation for iterators
local chain = function (it1, it2)
return wrap(
function()
local res = it1() or it2()
return res
end
)
end
register_method("chain", chain)
-- creates an iterator on a single value
p.singleton = function (val)
local iterated
return wrap(function()
if not iterated then
iterated = true
return val
end
end)
end
local function fold(it, acc, init)
local accum = init
for res in it do
accum = acc(res, accum)
end
return accum
end
register_method("fold", fold)
local function totable(it)
return fold(
it,
function (val, tabl)
table.insert(tabl, val)
return tabl
end,
{}
)
end
register_method("totable", totable)
function p.range(start_i, end_i, step)
local i = nil
step = step or 1
assert(step ~= 0)
local direction = step/math.abs(step)
return wrap(function()
if not i then
i = start_i
else
i = i + step
end
if i * direction < end_i * direction then
return i
else
return
end
end)
end
--------------------------------------------------------------------------------
-- TESTING FUNCTIONS
--------------------------------------------------------------------------------
function p.execute(iterator)
for x in iterator do
mw.log(x)
end
end
function p.execute_pair(iterator)
for x, y in iterator do
mw.log(x, y)
end
end
return p