Module:Iterateurs
La documentation pour ce module peut être créée à Module:Iterateurs/doc
--[[ --------------------------------------------------------------------------------- -- 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