--[[
---------------------------------------------------------------------------------
-- 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