123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- ---
- --- Lua Fun - a high-performance functional programming library for LuaJIT
- ---
- --- Copyright (c) 2013 Roman Tsisyk <roman@tsisyk.com>
- ---
- --- Distributed under the MIT/X11 License. See COPYING.md for more details.
- ---
-
- --------------------------------------------------------------------------------
- -- Tools
- --------------------------------------------------------------------------------
-
- local return_if_not_empty = function(state_x, ...)
- if state_x == nil then
- return nil
- end
- return ...
- end
-
- local call_if_not_empty = function(fun, state_x, ...)
- if state_x == nil then
- return nil
- end
- return state_x, fun(...)
- end
-
- local function deepcopy(orig) -- used by cycle()
- local orig_type = type(orig)
- local copy
- if orig_type == 'table' then
- copy = {}
- for orig_key, orig_value in next, orig, nil do
- copy[deepcopy(orig_key)] = deepcopy(orig_value)
- end
- else
- copy = orig
- end
- return copy
- end
-
- --------------------------------------------------------------------------------
- -- Basic Functions
- --------------------------------------------------------------------------------
-
- local nil_gen = function(_param, _state)
- return nil
- end
-
- local string_gen = function(param, state)
- local state = state + 1
- if state > #param then
- return nil
- end
- local r = string.sub(param, state, state)
- return state, r
- end
-
- local pairs_gen = pairs({ a = 0 }) -- get the generating function from pairs
- local map_gen = function(tab, key)
- local value
- local key, value = pairs_gen(tab, key)
- return key, key, value
- end
-
- local iter = function(obj, param, state)
- assert(obj ~= nil, "invalid iterator")
- if (type(obj) == "function") then
- return obj, param, state
- elseif (type(obj) == "table" or type(obj) == "userdata") then
- if #obj > 0 then
- return ipairs(obj)
- else
- return map_gen, obj, nil
- end
- elseif (type(obj) == "string") then
- if #obj == 0 then
- return nil_gen, nil, nil
- end
- return string_gen, obj, 0
- end
- error(string.format('object %s of type "%s" is not iterable',
- obj, type(obj)))
- end
-
- local iter_tab = function(obj)
- if type(obj) == "function" then
- return obj, nil, nil
- elseif type(obj) == "table" and type(obj[1]) == "function" then
- return obj[1], obj[2], obj[3]
- else
- return iter(obj)
- end
- end
-
- local each = function(fun, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- repeat
- state_x = call_if_not_empty(fun, gen_x(param_x, state_x))
- until state_x == nil
- end
-
- --------------------------------------------------------------------------------
- -- Generators
- --------------------------------------------------------------------------------
-
- local range_gen = function(param, state)
- local stop, step = param[1], param[2]
- local state = state + step
- if state >= stop then
- return nil
- end
- return state, state
- end
-
- local range_rev_gen = function(param, state)
- local stop, step = param[1], param[2]
- local state = state + step
- if state <= stop then
- return nil
- end
- return state, state
- end
-
- local range = function(start, stop, step)
- if step == nil then
- step = 1
- if stop == nil then
- stop = start
- start = 0
- end
- end
-
- assert(type(start) == "number", "start must be a number")
- assert(type(stop) == "number", "stop must be a number")
- assert(type(step) == "number", "step must be a number")
- assert(step ~= 0, "step must not be zero")
-
- if (step > 0) then
- return range_gen, {stop, step}, start - step
- elseif (step < 0) then
- return range_rev_gen, {stop, step}, start - step
- end
- end
-
- local duplicate_table_gen = function(param_x, state_x)
- return state_x + 1, unpack(param_x)
- end
-
- local duplicate_fun_gen = function(param_x, state_x)
- return state_x + 1, param_x(state_x)
- end
-
- local duplicate_gen = function(param_x, state_x)
- return state_x + 1, param_x
- end
-
- local duplicate = function(...)
- if select('#', ...) <= 1 then
- return duplicate_gen, select(1, ...), 0
- else
- return duplicate_table_gen, {...}, 0
- end
- end
-
- local tabulate = function(fun)
- assert(type(fun) == "function")
- return duplicate_fun_gen, fun, 0
- end
-
- local zeros = function()
- return duplicate_gen, 0, 0
- end
-
- local ones = function()
- return duplicate_gen, 1, 0
- end
-
- local rands_gen = function(param_x, _state_x)
- return 0, math.random(param_x[1], param_x[2])
- end
-
- local rands_nil_gen = function(_param_x, _state_x)
- return 0, math.random()
- end
-
- local rands = function(n, m)
- if n == nil and m == nil then
- return rands_nil_gen, 0, 0
- end
- assert(type(n) == "number", "invalid first arg to rands")
- if m == nil then
- m = n
- n = 0
- else
- assert(type(m) == "number", "invalid second arg to rands")
- end
- assert(n < m, "empty interval")
- return rands_gen, {n, m - 1}, 0
- end
-
- --------------------------------------------------------------------------------
- -- Slicing
- --------------------------------------------------------------------------------
-
- local nth = function(n, gen, param, state)
- assert(n > 0, "invalid first argument to nth")
- local gen_x, param_x, state_x = iter(gen, param, state)
- -- An optimization for arrays and strings
- if gen_x == ipairs then
- return param_x[n]
- elseif gen_x == string_gen then
- if n < #param_x then
- return string.sub(param_x, n, n)
- else
- return nil
- end
- end
- for i=1,n-1,1 do
- state_x = gen_x(param_x, state_x)
- if state_x == nil then
- return nil
- end
- end
- return return_if_not_empty(gen_x(param_x, state_x))
- end
-
- local head_call = function(state, ...)
- if state == nil then
- error("head: iterator is empty")
- end
- return ...
- end
-
- local head = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return head_call(gen_x(param_x, state_x))
- end
-
- local tail = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- state_x = gen_x(param_x, state_x)
- if state_x == nil then
- return nil_gen, nil, nil
- end
- return gen_x, param_x, state_x
- end
-
- local take_n_gen_x = function(i, state_x, ...)
- if state_x == nil then
- return nil
- end
- return {i, state_x}, ...
- end
-
- local take_n_gen = function(param, state)
- local n, gen_x, param_x = param[1], param[2], param[3]
- local i, state_x = state[1], state[2]
- if i >= n then
- return nil
- end
- return take_n_gen_x(i + 1, gen_x(param_x, state_x))
- end
-
- local take_n = function(n, gen, param, state)
- assert(n >= 0, "invalid first argument to take_n")
- local gen_x, param_x, state_x = iter(gen, param, state)
- return take_n_gen, {n, gen, param}, {0, state}
- end
-
- local take_while_gen_x = function(fun, state_x, ...)
- if state_x == nil or not fun(...) then
- return nil
- end
- return state_x, ...
- end
-
- local take_while_gen = function(param, state_x)
- local fun, gen_x, param_x = param[1], param[2], param[3]
- return take_while_gen_x(fun, gen_x(param_x, state_x))
- end
-
- local take_while = function(fun, gen, param, state)
- assert(type(fun) == "function", "invalid first argument to take_while")
- local gen_x, param_x, state_x = iter(gen, param, state)
- return take_while_gen, {fun, gen, param}, state
- end
-
- local take = function(n_or_fun, gen, param, state)
- if type(n_or_fun) == "number" then
- return take_n(n_or_fun, gen, param, state)
- else
- return take_while(n_or_fun, gen, param, state)
- end
- end
-
- local drop_n = function(n, gen, param, state)
- assert(n >= 0, "invalid first argument to drop_n")
- local gen_x, param_x, state_x = iter(gen, param, state)
- for i=1,n,1 do
- state_x = gen_x(param_x, state_x)
- if state_x == nil then
- return nil_gen, nil, nil
- end
- end
- return gen_x, param_x, state_x
- end
-
- local drop_while_x = function(fun, state_x, ...)
- if state_x == nil or not fun(...) then
- return state_x, false
- end
- return state_x, true, ...
- end
-
- local drop_while = function(fun, gen, param, state)
- assert(type(fun) == "function", "invalid first argument to drop_while")
- local gen_x, param_x, state_x = iter(gen, param, state)
- local cont, state_x_prev
- repeat
- state_x_prev = deepcopy(state_x)
- state_x, cont = drop_while_x(fun, gen_x(param_x, state_x))
- until not cont
- if state_x == nil then
- return nil_gen, nil, nil
- end
- return gen_x, param_x, state_x_prev
- end
-
- local drop = function(n_or_fun, gen, param, state)
- if type(n_or_fun) == "number" then
- return drop_n(n_or_fun, gen, param, state)
- else
- return drop_while(n_or_fun, gen, param, state)
- end
- end
-
- local split = function(n_or_fun, gen, param, state)
- return {take(n_or_fun, gen, param, state)},
- {drop(n_or_fun, gen, param, state)}
- end
-
- --------------------------------------------------------------------------------
- -- Indexing
- --------------------------------------------------------------------------------
-
- local index = function(x, gen, param, state)
- local i = 1
- for _k, r in iter(gen, param, state) do
- if r == x then
- return i
- end
- i = i + 1
- end
- return nil
- end
-
- local indexes_gen = function(param, state)
- local x, gen_x, param_x = param[1], param[2], param[3]
- local i, state_x = state[1], state[2]
- local r
- while true do
- state_x, r = gen_x(param_x, state_x)
- if state_x == nil then
- return nil
- end
- i = i + 1
- if r == x then
- return {i, state_x}, i
- end
- end
- end
-
- local indexes = function(x, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return indexes_gen, {x, gen_x, param_x}, {0, state_x}
- end
-
- -- TODO: undocumented
- local find = function(fun, gen, param, state)
- local gen_x, param_x, state_x = filter(fun, gen, param, state)
- return return_if_not_empty(gen_x(param_x, state_x))
- end
-
- --------------------------------------------------------------------------------
- -- Filtering
- --------------------------------------------------------------------------------
-
- local filter1_gen = function(fun, gen_x, param_x, state_x, a)
- while true do
- if state_x == nil or fun(a) then break; end
- state_x, a = gen_x(param_x, state_x)
- end
- return state_x, a
- end
-
- -- call each other
- local filterm_gen
- local filterm_gen_shrink = function(fun, gen_x, param_x, state_x)
- return filterm_gen(fun, gen_x, param_x, gen_x(param_x, state_x))
- end
-
- filterm_gen = function(fun, gen_x, param_x, state_x, ...)
- if state_x == nil then
- return nil
- end
- if fun(...) then
- return state_x, ...
- end
- return filterm_gen_shrink(fun, gen_x, param_x, state_x)
- end
-
- local filter_detect = function(fun, gen_x, param_x, state_x, ...)
- if select('#', ...) < 2 then
- return filter1_gen(fun, gen_x, param_x, state_x, ...)
- else
- return filterm_gen(fun, gen_x, param_x, state_x, ...)
- end
- end
-
- local filter_gen = function(param, state_x)
- local fun, gen_x, param_x = param[1], param[2], param[3]
- return filter_detect(fun, gen_x, param_x, gen_x(param_x, state_x))
- end
-
- local filter = function(fun, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return filter_gen, {fun, gen_x, param_x}, state_x
- end
-
- local grep = function(fun_or_regexp, gen, param, state)
- local fun = fun_or_regexp
- if type(fun_or_regexp) == "string" then
- fun = function(x) return string.find(x, fun_or_regexp) ~= nil end
- end
- return filter(fun, gen, param, state)
- end
-
- local partition = function(fun, gen, param, state)
- local neg_fun = function(...)
- return not fun(...)
- end
- local gen_x, param_x, state_x = iter(gen, param, state)
- return {filter(fun, gen_x, param_x, state_x)},
- {filter(neg_fun, gen_x, param_x, state_x)}
- end
-
- --------------------------------------------------------------------------------
- -- Reducing
- --------------------------------------------------------------------------------
-
- local foldl_call = function(fun, start, state, ...)
- if state == nil then
- return nil, start
- end
- return state, fun(start, ...)
- end
-
- local foldl = function(fun, start, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- while true do
- state_x, start = foldl_call(fun, start, gen_x(param_x, state_x))
- if state_x == nil then
- break;
- end
- end
- return start
- end
-
- local length = function(gen, param, state)
- local gen, param, state = iter(gen, param, state)
- if gen == ipairs or gen == string_gen then
- return #param
- end
- local len = 0
- repeat
- state = gen(param, state)
- len = len + 1
- until state == nil
- return len - 1
- end
-
- local is_null = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return gen_x(param_x, deepcopy(state_x)) == nil
- end
-
- local is_prefix_of = function(iter_x, iter_y)
- local gen_x, param_x, state_x = iter_tab(iter_x)
- local gen_y, param_y, state_y = iter_tab(iter_y)
-
- local r_x, r_y
- for i=1,10,1 do
- state_x, r_x = gen_x(param_x, state_x)
- state_y, r_y = gen_y(param_y, state_y)
- if state_x == nil then
- return true
- end
- if state_y == nil or r_x ~= r_y then
- return false
- end
- end
- end
-
- local all = function(fun, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local r
- repeat
- state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))
- until state_x == nil or not r
- return state_x == nil
- end
-
- local any = function(fun, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local r
- repeat
- state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))
- until state_x == nil or r
- return not not r
- end
-
- local sum = function(gen, param, state)
- local gen, param, state = iter(gen, param, state)
- local s = 0
- local r = 0
- repeat
- s = s + r
- state, r = gen(param, state)
- until state == nil
- return s
- end
-
- local product = function(gen, param, state)
- local gen, param, state = iter(gen, param, state)
- local p = 1
- local r = 1
- repeat
- p = p * r
- state, r = gen(param, state)
- until state == nil
- return p
- end
-
- local min_cmp = function(m, n)
- if n < m then return n else return m end
- end
-
- local max_cmp = function(m, n)
- if n > m then return n else return m end
- end
-
- local min = function(gen, param, state)
- local gen, param, state = iter(gen, param, state)
- local state, m = gen(param, state)
- if state == nil then
- error("min: iterator is empty")
- end
-
- local cmp
- if type(m) == "number" then
- -- An optimization: use math.min for numbers
- cmp = math.min
- else
- cmp = min_cmp
- end
-
- for _, r in gen, param, state do
- m = cmp(m, r)
- end
- return m
- end
-
- local min_by = function(cmp, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local state_x, m = gen_x(param_x, state_x)
- if state_x == nil then
- error("min: iterator is empty")
- end
-
- for _, r in gen_x, param_x, state_x do
- m = cmp(m, r)
- end
- return m
- end
-
- local max = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local state_x, m = gen_x(param_x, state_x)
- if state_x == nil then
- error("max: iterator is empty")
- end
-
- local cmp
- if type(m) == "number" then
- -- An optimization: use math.max for numbers
- cmp = math.max
- else
- cmp = max_cmp
- end
-
- for _, r in gen_x, param_x, state_x do
- m = cmp(m, r)
- end
- return m
- end
-
- local max_by = function(cmp, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local state_x, m = gen_x(param_x, state_x)
- if state_x == nil then
- error("max: iterator is empty")
- end
-
- for _, r in gen_x, param_x, state_x do
- m = cmp(m, r)
- end
- return m
- end
-
- local totable = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local tab, key, val = {}
- while true do
- state_x, val = gen_x(param_x, state_x)
- if state_x == nil then
- break
- end
- table.insert(tab, val)
- end
- return tab
- end
-
- local tomap = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- local tab, key, val = {}
- while true do
- state_x, key, val = gen_x(param_x, state_x)
- if state_x == nil then
- break
- end
- tab[key] = val
- end
- return tab
- end
-
- --------------------------------------------------------------------------------
- -- Transformations
- --------------------------------------------------------------------------------
-
- local map_gen = function(param, state)
- local gen_x, param_x, fun = param[1], param[2], param[3]
- return call_if_not_empty(fun, gen_x(param_x, state))
- end
-
- local map = function(fun, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return map_gen, {gen_x, param_x, fun}, state_x
- end
-
- local enumerate_gen_call = function(state, i, state_x, ...)
- if state_x == nil then
- return nil
- end
- return {i + 1, state_x}, i, ...
- end
-
- local enumerate_gen = function(param, state)
- local gen_x, param_x = param[1], param[2]
- local i, state_x = state[1], state[2]
- return enumerate_gen_call(state, i, gen_x(param_x, state_x))
- end
-
- local enumerate = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return enumerate_gen, {gen_x, param_x}, {0, state_x}
- end
-
- local intersperse_call = function(i, state_x, ...)
- if state_x == nil then
- return nil
- end
- return {i + 1, state_x}, ...
- end
-
- local intersperse_gen = function(param, state)
- local x, gen_x, param_x = param[1], param[2], param[3]
- local i, state_x = state[1], state[2]
- if i % 2 == 1 then
- return {i + 1, state_x}, x
- else
- return intersperse_call(i, gen_x(param_x, state_x))
- end
- end
-
- -- TODO: interperse must not add x to the tail
- local intersperse = function(x, gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return intersperse_gen, {x, gen_x, param_x}, {0, state_x}
- end
-
- --------------------------------------------------------------------------------
- -- Compositions
- --------------------------------------------------------------------------------
-
- local function zip_gen_r(param, state, state_new, ...)
- if #state_new == #param / 2 then
- return state_new, ...
- end
-
- local i = #state_new + 1
- local gen_x, param_x = param[2 * i - 1], param[2 * i]
- local state_x, r = gen_x(param_x, state[i])
- -- print('i', i, 'state_x', state_x, 'r', r)
- if state_x == nil then
- return nil
- end
- table.insert(state_new, state_x)
- return zip_gen_r(param, state, state_new, r, ...)
- end
-
- local zip_gen = function(param, state)
- return zip_gen_r(param, state, {})
- end
-
- local zip = function(...)
- local n = select('#', ...)
- if n == 0 then
- return nil_gen, nil, nil
- end
- local param = { [2 * n] = 0 }
- local state = { [n] = 0 }
-
- local i, gen_x, param_x, state_x
- for i=1,n,1 do
- local elem = select(n - i + 1, ...)
- gen_x, param_x, state_x = iter_tab(elem)
- param[2 * i - 1] = gen_x
- param[2 * i] = param_x
- state[i] = state_x
- end
-
- return zip_gen, param, state
- end
-
- local cycle_gen_call = function(param, state_x, ...)
- if state_x == nil then
- local gen_x, param_x, state_x0 = param[1], param[2], param[3]
- return gen_x(param_x, deepcopy(state_x0))
- end
- return state_x, ...
- end
-
- local cycle_gen = function(param, state_x)
- local gen_x, param_x, state_x0 = param[1], param[2], param[3]
- return cycle_gen_call(param, gen_x(param_x, state_x))
- end
-
- local cycle = function(gen, param, state)
- local gen_x, param_x, state_x = iter(gen, param, state)
- return cycle_gen, {gen_x, param_x, state_x}, deepcopy(state_x)
- end
-
- -- call each other
- local chain_gen_r1
- local chain_gen_r2 = function(param, state, state_x, ...)
- if state_x == nil then
- local i = state[1]
- i = i + 1
- if i > #param / 3 then
- return nil
- end
- local state_x = param[3 * i]
- return chain_gen_r1(param, {i, state_x})
- end
- return {state[1], state_x}, ...
- end
-
- chain_gen_r1 = function(param, state)
- local i, state_x = state[1], state[2]
- local gen_x, param_x = param[3 * i - 2], param[3 * i - 1]
- return chain_gen_r2(param, state, gen_x(param_x, state[2]))
- end
-
- local chain = function(...)
- local n = select('#', ...)
- if n == 0 then
- return nil_gen, nil, nil
- end
-
- local param = { [3 * n] = 0 }
- local i, gen_x, param_x, state_x
- for i=1,n,1 do
- local elem = select(i, ...)
- gen_x, param_x, state_x = iter_tab(elem)
- param[3 * i - 2] = gen_x
- param[3 * i - 1] = param_x
- param[3 * i] = state_x
- end
-
- return chain_gen_r1, param, {1, param[3]}
- end
-
- --------------------------------------------------------------------------------
- -- Operators
- --------------------------------------------------------------------------------
-
- operator = {
- ----------------------------------------------------------------------------
- -- Comparison operators
- ----------------------------------------------------------------------------
- lt = function(a, b) return a < b end,
- le = function(a, b) return a <= b end,
- eq = function(a, b) return a == b end,
- ne = function(a, b) return a ~= b end,
- ge = function(a, b) return a >= b end,
- gt = function(a, b) return a > b end,
-
- ----------------------------------------------------------------------------
- -- Arithmetic operators
- ----------------------------------------------------------------------------
- add = function(a, b) return a + b end,
- div = function(a, b) return a / b end,
- floordiv = function(a, b) return math.floor(a/b) end,
- intdiv = function(a, b)
- local q = a / b
- if a >= 0 then return math.floor(q) else return math.ceil(q) end
- end,
- mod = function(a, b) return a % b end,
- mul = function(a, b) return a * b end,
- neq = function(a) return -a end,
- unm = function(a) return -a end, -- an alias
- pow = function(a, b) return a ^ b end,
- sub = function(a, b) return a - b end,
- truediv = function(a, b) return a / b end,
-
- ----------------------------------------------------------------------------
- -- String operators
- ----------------------------------------------------------------------------
- concat = function(a, b) return a..b end,
- len = function(a) return #a end,
- length = function(a) return #a end, -- an alias
-
- ----------------------------------------------------------------------------
- -- Logical operators
- ----------------------------------------------------------------------------
- land = function(a, b) return a and b end,
- lor = function(a, b) return a or b end,
- lnot = function(a) return not a end,
- truth = function(a) return not not a end,
- }
-
- --------------------------------------------------------------------------------
- -- module definitions
- --------------------------------------------------------------------------------
-
- local exports = {
- ----------------------------------------------------------------------------
- -- Basic
- ----------------------------------------------------------------------------
- iter = iter,
- each = each,
- for_each = each, -- an alias
- foreach = each, -- an alias
-
- ----------------------------------------------------------------------------
- -- Generators
- ----------------------------------------------------------------------------
- range = range,
- duplicate = duplicate,
- xrepeat = duplicate, -- an alias
- replicate = duplicate, -- an alias
- tabulate = tabulate,
- ones = ones,
- zeros = zeros,
- rands = rands,
-
- ----------------------------------------------------------------------------
- -- Slicing
- ----------------------------------------------------------------------------
- nth = nth,
- head = head,
- car = head, -- an alias
- tail = tail,
- cdr = tail, -- an alias
- take_n = take_n,
- take_while = take_while,
- take = take,
- drop_n = drop_n,
- drop_while = drop_while,
- drop = drop,
- split = split,
- split_at = split, -- an alias
- span = split, -- an alias
-
- ----------------------------------------------------------------------------
- -- Indexing
- ----------------------------------------------------------------------------
- index = index,
- index_of = index, -- an alias
- elem_index = index, -- an alias
- indexes = indexes,
- indices = indexes, -- an alias
- elem_indexes = indexes, -- an alias
- elem_indices = indexes, -- an alias
- find = find,
-
- ----------------------------------------------------------------------------
- -- Filtering
- ----------------------------------------------------------------------------
- filter = filter,
- remove_if = filter, -- an alias
- grep = grep,
- partition = partition,
-
- ----------------------------------------------------------------------------
- -- Reducing
- ----------------------------------------------------------------------------
- foldl = foldl,
- reduce = foldl, -- an alias
- length = length,
- is_null = is_null,
- is_prefix_of = is_prefix_of,
- all = all,
- every = all, -- an alias
- any = any,
- some = any, -- an alias
- sum = sum,
- product = product,
- min = min,
- minimum = min, -- an alias
- min_by = min_by,
- minimum_by = min_by, -- an alias
- max = max,
- maximum = max, -- an alias
- max_by = max_by,
- maximum_by = max_by, -- an alias
- totable = totable,
- tomap = tomap,
-
- ----------------------------------------------------------------------------
- -- Transformations
- ----------------------------------------------------------------------------
- map = map,
- enumerate = enumerate,
- intersperse = intersperse,
-
- ----------------------------------------------------------------------------
- -- Compositions
- ----------------------------------------------------------------------------
- zip = zip,
- cycle = cycle,
- chain = chain,
-
- ----------------------------------------------------------------------------
- -- Operators
- ----------------------------------------------------------------------------
- operator = operator,
- op = operator -- an alias
- }
-
- -- a special syntax sugar to export all functions to the global table
- setmetatable(exports, {
- __call = function(t)
- for k, v in pairs(t) do _G[k] = v end
- end,
- })
-
- return exports
|