Utility functions - Yonaba/Moses GitHub Wiki

local M = require 'moses'

noop ()

The no-operation function. Takes nothing, returns nothing. It is being used internally.

M.noop() -- => nil

identity (value)

Returns the passed-in value.
This function is internally used as a default transformation function.

M.identity(1)-- => 1
M.identity(false) -- => false
M.identity('hello!') -- => 'hello!'

call (f [, ...])

Calls f with the supplied arguments. Returns the results of f(...).

M.call(math.pow, 2, 3) -- => 8
M.call(string.len, 'hello' ) -- => 5
M.call(table.concat, {1,2,3,4,5}, ',', 2, 4) -- => {2,3,4}

constant (value)

Creates a constant function. This function will continuously yield the same output.

local pi = M.constant(math.pi)
pi(1) -- => 3.1415926535898
pi(2) -- => 3.1415926535898
pi(math.pi) -- => 3.1415926535898

applySpec (specs)

Returns a function which applies specs on args. This function will produce an object having the same structure than specs by mapping each property to the result of calling its associated function with the supplied arguments.

local stats = M.applySpec({
  min = function(...) return math.min(...) end,
  max = function(...) return math.max(...) end,
})

stats(5,4,10,1,8) -- => {min = 1, max = 10}

thread (value [, ...])

Threads value through a series of functions.

local function inc(x) return x + 1 end
local function double(x) return 2 * x end
local function square(x) return x * x end
M.thread(2, inc, double, square) -- => 36
M.thread(3, double, inc, square) -- => 49
M.thread(4, square, double, inc) -- => 33
M.thread(5, square, inc, double) -- => 52

If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded.

local function inc(x) return x + 1 end
local function add(x, y) return x * y end
local function pow(x, y) return x ^ y end
M.thread(2, inc, {add, 3}, {pow, 2}) -- => 36
M.thread(2, {add, 4}, inc, {pow, 2}) -- => 49

threadRight (value [, ...])

Threads value through a series of functions. If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded. The value is used as the last input.

local function inc(x) return x + 1 end
local function add(x, y) return x * y end
local function pow(x, y) return x ^ y end
M.threadRight(2, inc, {add, 3}, {pow, 2}) -- => 64
M.threadRight(2, {add, 4}, inc, {pow, 2}) -- => 128

dispatch (...)

Returns a dispatching function. When called with arguments, this function invokes each of its functions in the passed-in order and returns the results of the first non-nil evaluation.

local f = M.dispatch(
  function() return nil end,
  function (v) return v+1 end, 
  function (v) return 2*v end
)
f(5) -- => 6
f(7) -- => 8

memoize (f)

Aliases: cache.

Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body.

local function fibonacci(n)
  return n < 2 and n or fibonacci(n-1)+fibonacci(n-2)
end  
local mem_fibonacci = M.memoize(fibonacci)
fibonacci(20) -- => 6765 (but takes some time)
mem_fibonacci(20) -- => 6765 (takes less time)

unfold (f, seed)

Builds a list from a seed value. Accepts an iterator function, which returns either nil to stop iteration or two values : the value to add to the list of results and the seed to be used in the next call to the iterator function.

local function f(v)
  if v < 100 then return v, v * 2 end
end
local t = M.unfold(f, 10) -- => {10,20,40,80}

once (f)

Produces a function that runs only once. Successive calls to this function will still yield the same input.

local sq = M.once(function(a) return a*a end)
sq(1) -- => 1
sq(2) -- => 1
sq(3) -- => 1
sq(4) -- => 1
sq(5) -- => 1

before (f, count)

Returns a version of f that will run no more than count times. Next calls will keep yielding the results of the (n-th)-1 call.

local function greet(someone) return 'hello '..someone end
local greetOnly3people = M.before(greet, 3)
greetOnly3people('John') -- => 'hello John'
greetOnly3people('Moe') -- => 'hello Moe'
greetOnly3people('James') -- => 'hello James'
greetOnly3people('Joseph') -- => 'hello James'
greetOnly3people('Allan') -- => 'hello James'

after (f, count)

Produces a function that will respond only after a given number of calls.

local f = M.after(M.identity,3)
f(1) -- => nil
f(2) -- => nil
f(3) -- => 3
f(4) -- => 4

compose (...)

Composes functions. Each function consumes the return value of the one that follows.

local function f(x) return x^2 end
local function g(x) return x+1 end
local function h(x) return x/2 end
local compositae = M.compose(f,g,h)
compositae(10) -- => 36
compositae(20) -- => 121

pipe (value, ...)

Pipes a value through a series of functions.

local function f(x) return x^2 end
local function g(x) return x+1 end
local function h(x) return x/2 end
M.pipe(10,f,g,h) -- => 36
M.pipe(20,f,g,h) -- => 121

complement (f)

Returns a function which returns the logical complement of a given function.

M.complement(function() return true end)() -- => false

juxtapose (value, ...)

Aliases: juxt.

Calls a sequence of functions with the same input.

local function f(x) return x^2 end
local function g(x) return x+1 end
local function h(x) return x/2 end
M.juxtapose(10, f, g, h) -- => 100, 11, 5

wrap (f, wrapper)

Wraps a function inside a wrapper. Allows the wrapper to execute code before and after function run.

local greet = function(name) return "hi: " .. name end
local greet_backwards = M.wrap(greet, function(f,arg)
  return f(arg) ..'\nhi: ' .. arg:reverse()
end) 
greet_backwards('John')

-- => hi: John
-- => hi: nhoJ

times (iter [, n])

Calls a given function n times.

local f = ('Lua programming'):gmatch('.')
M.times(f, 3) -- => {'L','u','a'}

bind (f, v)

Binds a value to be the first argument to a function.

local sqrt2 = M.bind(math.sqrt,2)
sqrt2() -- => 1.4142135623731

bind2 (f, v)

Binds a value to be the second argument to a function.

local last2 = M.bind(M.last,2)
last2({1,2,3,4,5,6}) -- => {5,6}

bindn (f, ...)

Binds a variable number of values to be the first arguments to a function.

local function out(...) return table.concat {...} end
local out = M.bindn(out,'OutPut',':',' ')
out(1,2,3) -- => OutPut: 123
out('a','b','c','d') -- => OutPut: abcd

bindall (obj, ...)

Binds methods to object. As such, when calling any of these methods, they will receive object as a first argument.

local window = {
	setPos = function(w,x,y) w.x, w.y = x, y end, 
	setName = function(w,name) w.name = name end,
	getName = function(w) return w.name end,
}
window = M.bindall(window, 'setPos', 'setName', 'getName')
window.setPos(10,15)
print(window.x, window.y) -- => 10,15

window.setName('fooApp')
print(window.name) -- => 'fooApp'

print(window.getName()) -- => 'fooApp'

cond (conds)

Returns a function which iterate over an array list of conditions. It invokes each predicate, passing it given values. It returns the value of the corresponding function of the first predicate to return a non-nil value

local multipleOf = M.cond({
  {function(v) return v%2==0 end, function(v) return v..' is multiple of 2' end},
  {function(v) return v%3==0 end, function(v) return v..' is multiple of 3' end},
  {function(v) return v%5==0 end, function(v) return v..' is multiple of 5' end},
  {function() return true end, function(v) return 'could not find an answer for '..v end}
})
for i = 15, 20 do
  print(multipleOf(i))
end

-- => 15 is multiple of 3
-- => 16 is multiple of 2
-- => could not find an answer for 17
-- => 18 is multiple of 2
-- => could not find an answer for 19
-- => 20 is multiple of 2

both (...)

Returns a validation function. Given a set of functions, the validation function evaluates to true only when all its funcs returns true.

local f = M.both(
	function(x) return x > 0 end,
	function(x) return x < 10 end,
	function(x) return x % 2 == 0 end
)
f(2) -- => true
f(8) -- => true
f(9) -- => false

either (...)

Returns a validation function. Given a set of functions, the validation function evaluates to true when one of its funcs returns true.

local f = M.either(
	function(x) return x > 0 end,
	function(x) return x % 2 == 0 end
)
f(0) -- => true
f(-3) -- => false

neither (...)

Returns a validation function. Given a set of functions, the validation function evaluates to true when neither of its funcs returns true.

local f = M.neither(
	function(x) return x > 10 end,
	function(x) return x % 2 == 0 end
)
f(12) -- => false
f(8) -- => false
f(7) -- => true

uniqueId ([template])

Aliases: uid.

Returns an unique integer ID.

M.uniqueId() -- => 1

Can handle string templates for formatted output.

M.uniqueId('ID%s') -- => 'ID2'

Or a function, for the same purpose.

local formatter = function(ID) return '$'..ID..'$' end
M.uniqueId(formatter) -- => '$ID1$'

iterator(f, value [, n])

Aliases: iter.

Returns an iterator function which constinuously applies a function f onto an input value. For example, let us go through the powers of two using iterator.

local function po2(x) return x*2 end
local function iter_po2 = M.iterator(po2, 1)
iter_po2() -- => 2
iter_po2() -- => 4
iter_po2() -- => 8

if n is supplied, it will run at maximum n times.

local function po2(x) return x*2 end
local function iter_po2 = M.iterator(po2, 1, 3)
iter_po2() -- => 2
iter_po2() -- => 4
iter_po2() -- => 8
iter_po2() -- => nil

skip (iter [, n = 1])

Consumes the first n values of a iterator then returns it.

local w = "hello"
local char = string.gmatch(w,'.')
local iter = M.skip(char, 3)
for w in iter do print(w) end -- => 'l', 'o'

n defaults to 1 when not given.

local w = "hello"
local char = string.gmatch(w,'.')
local iter = M.skip(char)
for w in iter do print(w) end -- => 'e', 'l', 'l', 'o'

tabulate (...)

Iterates a given iterator function and returns its values packed in an array.

local text = 'letters'
local chars = string.gmatch(text, '.')
M.tabulate(chars) -- => {'l','e','t','t','e','r','s'}

iterlen (...)

Returns the length of an iterator.

local text = 'letters'
local chars = string.gmatch(text, '.')
M.iterlen(chars) -- => 7

It consumes the iterator itself.

local text = 'lua'
local chars = string.gmatch(text, '.')
M.iterlen(chars) -- => 3
chars() -- => nil

castArray (value)

Casts the passed-in value to an array containing the value itself.

M.castArray(true) -- => {true}
M.castArray(2) -- => {2}

It leaves the given value untouched in case it is already a table.

local t = {1}
print(M.castArray(t) == t) -- => true

flip (f)

Creates a function of f with arguments flipped in reverse order.

local function f(...) return table.concat({...}) end
local flipped = M.flip(f)
flipped('a','b','c') -- => 'cba'

nthArg(n)

Returns a function that gets the nth argument.

local f = M.nthArg(3)
f('a','b','c') -- => 'c'

If n is negative, the nth argument from the end is returned.

local f = M.nthArg(-2)
f('a','b','c') -- => 'b'

unary (f)

Returns a function which accepts up to one argument. It ignores any additional arguments.

local f = M.unary(function (...) return ... end)
f('a') - ==> 'a'
f('a','b','c') -- => 'a'

ary (f [, n = 1])

Aliases: nAry.

Returns a function which accepts up to n args. It ignores any additional arguments.

local f = M.ary(function (...) return ... end, 2)
f(1,2) - ==> 1,2
f(1,2,3,4) -- => 1,2

If n is not given, it defaults to 1.

local f = M.unary(function (...) return ... end)
f('a','b','c') -- => 'a'

noarg (f)

Returns a function with an arity of 0. The new function ignores any arguments passed to it.

local f = M.noarg(function (x) return x or 'default' end)
f(1) -- => 'default'
f(function() end, 3) -- => 'default'

rearg (f, indexes)

Returns a function which runs with arguments arranged according to given indexes.

local f = M.rearg(function (...) return ... end, {5,4,3,2,1})
f('a','b','c','d','e') -- => 'e','d','c','b','a'

over (...)

Creates a function that invokes a set of transforms with the arguments it receives.
One can use use for example to get the tuple of min and max values from a set of values

local minmax = M.over(math.min, math.max)
minmax(5,10,12,4,3) -- => {3,12}

overEvery (...)

Creates a validation function. The returned function checks if all of the given predicates return truthy when invoked with the arguments it receives.

local function alleven(...) 
	for i, v in ipairs({...}) do 
		if v%2~=0 then return false end 
	end 
	return true 
end

local function allpositive(...)
	for i, v in ipairs({...}) do 
		if v < 0 then return false end 
	end 
	return true 	
end

local allok = M.overEvery(alleven, allpositive)

allok(2,4,-1,8) -- => false
allok(10,3,2,6) -- => false
allok(8,4,6,10) -- => true

overSome (...)

Creates a validation function. The returned function checks if any of the given predicates return truthy when invoked with the arguments it receives.

local function alleven(...) 
	for i, v in ipairs({...}) do 
		if v%2~=0 then return false end 
	end 
	return true 
end

local function allpositive(...)
	for i, v in ipairs({...}) do 
		if v < 0 then return false end 
	end 
	return true 	
end

local anyok = M.overSome(alleven,allpositive)

anyok(2,4,-1,8) -- => false
anyok(10,3,2,6) -- => true
anyok(-1,-5,-3) -- => false

overArgs (f, ...)

Creates a function that invokes f with its arguments transformed

local function f(x, y) return x, y end
local function triple(x) retun x*3 end
local function square(x) retun x^2 end
local new_f = M.overArgs(f, triple, square)

new_f(1,2) -- => 3, 4
new_f(10,10) -- => 30, 100

In case the number of arguments is greater than the number of transforms, the remaining args will be left as-is.

local function f(x, y, z) return x, y, z end
local function triple(x) retun x*3 end
local function square(x) retun x^2 end
local new_f = M.overArgs(f, triple, square)

new_f(1,2,3) -- => 3, 4, 3
new_f(10,10,10) -- => 30, 100, 10

converge (f, g, h)

Converges two functions into one.

local function pow2(x) return x*x end
local function pow3(x) return x*x*x end
local function sum(a,b) return a+b end
local poly = M.converge(sum, pow2, pow3)
poly(5) -- => 150 (ie. 5*5 + 5*5*5)

partial (f, ...)

Partially apply a function by filling in any number of its arguments.

local function diff(a, b) return a - b end
local diffFrom20 = M.partial(diff, 20) -- arg 'a' will be 20 by default
diffFrom20(5) -- => 15

The string '_' can be used as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but is rather left open to be supplied at call-time.

local function diff(a, b) return a - b end
local remove5 = M.partial(diff, '_', 5) -- arg 'a' will be given at call-time, but 'b' is set to 5
remove5(20) -- => 15

partialRight (f, ...)

Like M.partial, it partially applies a function by filling in any number of its arguments, but from the right.

local function concat(...) return table.concat({...},',') end
local concat_right = M.partialRight(concat,'a','b','c')
concat_right('d') -- => d,a,b,c

concat_right = M.partialRight(concat,'a','b')
concat_right('c','d') -- => c,d,a,b

concat_right = M.partialRight(concat,'a')
concat_right('b','c','d') -- => b,c,d,a

The string '_', as always, can be used as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but is rather left open to be supplied at call-time. In that case, the first args supplied at runtime will be used to fill the initial list of args while the remaining will be prepended.

local function concat(...) return table.concat({...},',') end
local concat_right = M.partialRight(concat,'a','_','c')
concat_right('d','b') -- => b,a,d,c

concat_right = M.partialRight(concat,'a','b','_')
concat_right('c','d') -- => d,a,b,c

concat_right = M.partialRight(concat,'_','a')
concat_right('b','c','d') -- => c,d,b,a

curry (f [, n_args = 2])

Curries a function. If the given function f takes multiple arguments, it returns another version of f that takes a single argument (the first of the arguments to the original function) and returns a new function that takes the remainder of the arguments and returns the result.

local function sumOf3args(x,y,z) return x + y + z end
local curried_sumOf3args = M.curry(sumOf3args, 3)
sumOf3args(1)(2)(3)) -- => 6
sumOf3args(0)(6)(9)) -- => 15

n_args defaults to 2.

local function product(x,y) return x * y end
local curried_product = M.curry(product)
curried_product(5)(4) -- => 20
curried_product(3)(-5) -- => -15
curried_product(0)(1) -- => 0

time (f [, ...])

Returns the execution time of f (...) in seconds and its results.

local function wait_count(n) 
	local i = 0
	while i < n do i = i + 1 end
	return i
end

local time, i = M.time(wait_count, 1e6) -- => 0.002 1000000
local time, i = M.time(wait_count, 1e7) -- => 0.018 10000000
⚠️ **GitHub.com Fallback** ⚠️