From: Vsevolod Stakhov Date: Mon, 16 Feb 2015 16:35:18 +0000 (+0000) Subject: Import lua-functional for plugins stuff. X-Git-Tag: 0.9.0~690 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=195bfd320c83a04728faf213b38346b18b28d5a0;p=rspamd.git Import lua-functional for plugins stuff. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index e4d701dd1..5842c30a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1011,6 +1011,9 @@ FOREACH(LUA_PLUGIN ${LUA_PLUGINS}) INSTALL(FILES "src/plugins/lua/${LUA_PLUGIN}" DESTINATION ${PLUGINSDIR}/lua/${_rp}) ENDFOREACH(LUA_PLUGIN) +# Install lua fun library +INSTALL(FILES "contrib/lua-fun/fun.lua" DESTINATION ${PLUGINSDIR}/fun.lua) + # Lua config INSTALL(CODE "FILE(MAKE_DIRECTORY \$ENV{DESTDIR}${CONFDIR}/lua)") FILE(GLOB_RECURSE LUA_CONFIGS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/conf/lua" diff --git a/contrib/lua-fun/COPYING.md b/contrib/lua-fun/COPYING.md new file mode 100644 index 000000000..42ee231eb --- /dev/null +++ b/contrib/lua-fun/COPYING.md @@ -0,0 +1,27 @@ +Copying +======= + +**Lua Fun** source codes, logo and documentation are distributed under the +**[MIT/X11 License]** - same as Lua and LuaJIT. + +Copyright (c) 2013 Roman Tsisyk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +[MIT/X11 License]: http://www.opensource.org/licenses/mit-license.php diff --git a/contrib/lua-fun/fun.lua b/contrib/lua-fun/fun.lua new file mode 100644 index 000000000..5d019d6a1 --- /dev/null +++ b/contrib/lua-fun/fun.lua @@ -0,0 +1,968 @@ +--- +--- Lua Fun - a high-performance functional programming library for LuaJIT +--- +--- Copyright (c) 2013 Roman Tsisyk +--- +--- 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