Module:Iterateurs

 Documentation
--[[----------------------------------------------------------------------------------- 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 Luafunlocal methods = {} -- collects the methods to append to an iterator objectlocal register_method = (function(module, methods)return function(name, func)module[name] = funcmethods[name] = funcendend)(p, methods)-- the metatable for an iterator objectlocal 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 iteratorlocal wrap = function(gen, param, state)    return setmetatable({        gen = gen,        param = param,        state = state    }, iterator_mt), param, stateendp.wrap = wraplocal method0 = function(fun)    return function(self)        return fun(self.gen, self.param, self.state)    endendlocal methodn = function(fun)    return function(self, ...)        return fun(self.gen, ...)    endend---------------------------------------------------------- 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 keyslocal function map(it, transformation)assert(it, "map : no iterator provided")return wrap(function()local val = it()if val then return transformation(val) endend)endregister_method("map", map)-- like "map" except it works on pairs of values (usually key/val pairs)-- this iterator works on pairslocal 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) endend)endregister_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 valueslocal 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)) doval = it()endreturn valend)endregister_method("filter", filter)-- pair version of the previous function--this iterators works on pairslocal 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)) doi, val = it()endreturn i, valend)endregister_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 pairslocal function select_keys(it)assert(it, "select_keys : no iterator provided")return wrap(function()local i, val = it()return iend)endregister_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 pairslocal function select_vals(it)assert(it, "pair_vals : no iterator provided")return wrap(function()local i, val = it()return valend)endp.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 thenlocal i, res = _f(_s, _v)_v = iif not res then _s = nil endreturn resendend)endp.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 thenlocal i, res = _f(_s, _v)_v = iif not res then _s = nil endreturn i, resendend--)endp.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 thenlocal sub_it = creator(main_val)return wrap(function()if main_val thenlocal val = nilwhile not val and main_val doif sub_it thenval = sub_it()endif not val thenmain_val = it()if not main_val then return endsub_it = creator(main_val)endendreturn valendend)elsereturn wrap(function () return nil end)endendregister_method("flatten", flatten)-- equivalent of list concatenation for iteratorslocal chain = function (it1, it2)return wrap(function()local res = it1() or it2()return resend)endregister_method("chain", chain)-- creates an iterator on a single valuep.singleton = function (val)local iteratedreturn wrap(function()if not iterated theniterated = truereturn valendend)endlocal function fold(it, acc, init)local accum = initfor res in it doaccum = acc(res, accum)endreturn accumendregister_method("fold", fold)local function totable(it)return fold(it, function (val, tabl)table.insert(tabl, val)return tablend,{})endregister_method("totable", totable)function p.range(start_i, end_i, step)local i = nilstep = step or 1assert(step ~= 0)local direction = step/math.abs(step)return wrap(function()if not i then i = start_ielsei = i + stependif i * direction < end_i * direction then return ielsereturnendend)end---------------------------------------------------------------------------------- TESTING FUNCTIONS--------------------------------------------------------------------------------function p.execute(iterator)for x in iterator domw.log(x)endendfunction p.execute_pair(iterator)for x, y in iterator domw.log(x, y)endendreturn p