This module contains several functions and higher order functions or
decorators, mostly useful with HOF like map
, reduce
or in generators.
Indeed, using HOF often require some classical functions like constants one, identity, or classical operators.
Most of the times, these functions needs to be unary ones, i.e. have only one parameter. This module contains, among others, functions helping in the arity conversion of such functions:
curry
that makes a function automatically partializable,uncurry
that is the reverse of curry
,unary
and spreader
that convert a polyadic function into a unary
function taking an array or a tuple of values instead of several
values,varargs
which is the reverse of unary
Most of the binary operator functions defined here are curried. To ease
partialization, the non commutative operators have a reversed version, with
arguments swapped.
For example, using the reverse division operator rdiv
with
map
[2, 4, 8]: map(rdiv(2)) == [1, 2, 4]
The identity function id
, the constant function
const
, together with composition (FunctionReference::andThen
,
pipe
, compose
) and io
can be
used to create monad-like processing chains.
Polymorphic addition and concatenation.
Adds value
to element
.
The behavior depends on the type of element
:
+
;add
and returning the collection;Appendable
or a StringBuilder
, equivalent to invoking append
and
returning the collection.This function is swapped and curried. For instance:
add("b", "a") == "ab"
list[1, 2, 3]: map(add(3)) == list[4, 5, 6]
add("a", StringBuilder()): toString() == "a"
let f = add(42): andThen(add(1337)): andThen(add(69))
f(list[]) == list[42, 1337, 69]
f(0) == 1448
f(StringBuilder()): toString() == "42133769"
value
: the value to addelement
: the element to add the value toSee also addTo
Not swapped version of add
Curried boolean and.
This implementation is lazy.
The arguments can be boolean expressions or predicate functions. If called with predicate functions, returns a new predicate function.
`and(a, b) == (a and b)
`and(gt(10), ^even) == |x| -> a > 10 and x % 2 == 0
Function composition.
compose(f1, f2, f3)(x) == f1(f2(f3(x)))
This is similar to pipe
, but with functions order
reversed (B combinator).
Conditional application combinator.
Equivalent to using the match
construct:
let r = cond(predicate, ifTrue, ifFalse, x)
# equivalent to
let r = match {
when predicate(x) then ifTrue(x)
otherwise ifFalse(x)
}
Since this function is curried, it can be used as:
let f = cond(predicate, ifTrue, ifFalse)
# equivalent to
let f = |x| -> match {
when predicate(x) then ifTrue(x)
otherwise ifFalse(x)
}
predicate
a boolean functionifTrue
the unary function to apply if predicate
holdsifFalse
the unary function to apply otherwiseThe constant function.
Returns a new variadic functions that always returns val
, ignoring its
arguments. For example:
let theAnswerTo = const(42)
theAnswerTo() == 42
theAnswerTo(1, 2, 3) == 42
theAnswerTo("Life, the Universe and Everything") == 42
One interesting use case is to write “pipe” like composition, with the argument on the left:
const(42): andThen(f): andThen(g): andThen(h)() == h(g(f(42)))
This is also the K combinator.
Swapped curried containment test.
Checks if collection
contains value
.
The collection object can be anything with a contains
method.
For instance:
let predicate = contains(42)
if (predicate(collection)) {
...
}
value
: the value to test for containmentcollection
: any object having a contains
methodFunction to curryfy a function, i.e. transforms a polyadic function into a sequence of variadic functions. This allows for automatic partial application.
This is equivalent to applying invokeOrBind
on each call.
E.g.
function f = |a, b, c| -> a + b + c
let g = curry(^f)
g(29)(10)(3) == f(29, 10, 3)
g(29, 10)(3) == 42
g(29)(10, 3) == 42
let g1 = g(29)
let g2 = g1(10)
let g3 = g(29, 10)
g(29, 10, 3) == 42
g1(10, 3) == 42
g1(10)(3) == 42
g2(3) == 42
g3(3) == 42
This is particularly useful to allow composing polyadic functions. For
instance, with the previous g
:
let h = g(2, 20): andThen(g("The answer", " is "))
h(20) == "The answer is 42"
If the function is variadic, only the fixed parameters can be partialized. For instance, given:
@!curry
function f = |a, b, c...| -> ...
...
let g = f(1, 2)
then g
is a variadic function that can't be called partially. All the
following calls are valids:
g()
g(1)
g(1, 2, 3)
but
g(1)(2)
is not.
This function can also be used as a decorator.
f
the function to curryf
that can be partializedSee also uncurry
Checks if the value is even.
See also odd
false
constant function.
First element of a list, tuple, vector, array.
fst([a, b]) == a
t
: any object with a get
method and at least one element.IndexOutOfBoundsException
if the object is empty.Curried swapped greater than or equal.
ge(a, b) == (b >= a)
Note: this function is swapped to make curried version more readable.
Curried indexing.
getitem(obj, i) == obj: get(i)
Throws an IndexOutOfBoundsException
(for a collection-like object) or returns
null
(for a map-like object) if the index is not present.
obj
: any object having a get
methodi
: the index to getCurried swapped greater than.
gt(a, b) == b > a
Note: this function is swapped to make curried version more readable.
The identity function.
Returns it's argument unchanged. This can be useful with higher order functions (I combinator).
Reversed curried function application.
Apply the given function to the given value.
invokeWith("a", "b", "c")(f) == f("a", "b", "c")
For instance, given a list of functions:
list[f, g, h]: map(invokeWith(42)) == list[f(42), g(42), h(42)]
It can also be used to promote a value in continuation passing style.
args
the values on which apply the functionTransform a function with side effects (generally IO operations, thus the name)
into a function applying the side effect. If the wrapped function returns
null
, its argument is return instead.
The given function can have no parameters, or accept an argument.
This can be used to insert such a function into a composition chain:
f1: andThen(io({println("hello")})): andThen(f2)
is an anonymous function equivalent to:
|x| {
var result = f1(x)
println("hello")
return f2(result)
}
and
f1: andThen(io(|x|{println("got " + x)})): andThen(f2)
is an anonymous function equivalent to:
|x| {
var result = f1(x)
println("got " + result)
return f2(result)
}
One last example with reading IO effect:
f1: andThen(io(|x| {
println("Got " + x)
return x + intValue(readln("Value to add? "))})
: andThen(f2)
is an anonymous function equivalent to:
|x| {
var result = f1(x)
println("Got " + x)
result = result + intValue(readln("Value to add? "))
return f2(result)
}
block
a function with side effectsCurried identity comparison
`is(ref, obj) == obj is ref
Parameters are swapped to ease partialization, as in:
lst: filter(is(ref))
Emptiness test.
Checks if the collection-like argument is empty.
Curried difference comparison
`isnt(ref, obj) = obj isnt ref
Like is
, this is more useful partialized. For instance:
lst: filter(`isnt(null))
Curried swapped less than or equal.
le(a, b) == (a <= b)
Note: this function is swapped to make curried version more readable.
Curried swapped less than.
lt(a, b) == b < a
lt(42) == |x| -> x < 42
Note: this function is swapped to make curried version more readable: lt(42)
is a predicate testing if its argument is “less than 42”.
Opposite (negative value).
neg(x) == -x
Same as mul(-1)
Polymorphic negation function.
E.g.
list[true, false, false]: map(^not) == list[false, true, true]
let even = |a| -> (a % 2) == 0
let odd = `not(even)
null
constant function.
Checks if the value is odd.
See also even
Curried type checking
`oftype(type, obj) = obj oftype type
Partialized version can be used as a predicate, for instance in filter
:
alist: filter(`oftype(String.class))
Curried boolean or.
`or(a, b) == (a or b)
This implementation is lazy.
The arguments can be boolean expressions or predicate functions. If called with predicate functions, returns a new predicate function.
Null value substitution
`orIfNull(0, 3) == 3
`orIfNull(0, null) == 0
This function can be useful, for example, to replace null
values in a list with
a map:
list[1, 2, null, 3]:map(`orIfNull(0)) == list[1, 2, 0, 3]
Function chaining.
This is similar to Unix pipe:
pipe(f1, f2, f3)(x) == f3(f2(f1(x))))
i.e. apply f1
to x
, then pass it to f2
, and then f3
.
This is the same as f1: andThen(f2): andThen(f3)(x)
You can insert a side-effect only function in the chain using io
:
pipe(f1, io({println("hello")}), f2)(42)
is equivalent to:
let tmp = f1(x)
println("hello")
f2(tmp)
This is similar to compose
, but with functions order
reversed.
Example:
let cmd = pipe(mul(2), add(4), ^toString, addTo("val: "))
cmd(19) == "val: 42"
let other = pipe(^intValue, add(4), mul(2))
other("17") == 42
If no function is given, returns id
For a similar construct that deal with errors, see for instance the
gololang.Errors
module
Fixed-point combinator.
This is an abstraction of recursion.
f
the function that will recurf
Curried indexed assignment
setitem(obj, i, v) == obj: set(i, v)
obj
: any object having a set
methodi
: the index to setv
: the value to setSecond element of a list, tuple, vector, array.
snd([a, b]) == b
t
: any object with a get
method and at least two elements.IndexOutOfBoundsException
if the object has less than 2 elements.Convers a polyadic function into an unary function.
Similar to unary
but using spread
instead of invoke
.
This function can also be used as a decorator.
See also varargs
Converts its argument to a String
.
Polymorphic swapping.
This function dispatches on swapArgs
,
swapCurry
or swapCouple
according
to its parameter.
Note that we have the property that given a binary function f
and a
couple c
unary(f)(swap(c)) == unary(swap(f))(c)
When applied to functions, equivalent to the C combinator.
Change the signature of the given binary function by swapping its arguments, such that:
swapArgs(f)(b, a) == f(a, b)
Warning: when using this function with one previously wrapped in
curry
or uncurry
, the resulting function can't be
automatically partialized any more.
Swap the values of a couple.
The couple can be a tuple, a vector, a list or an array as long as its size is 2. The return value as the same type.
For example:
swap([a, b]) == [b, a]
Change the signature of the given curried binary function by swapping its arguments, such that:
swapCurry(f)(a)(b) = f(b)(a)
true
constant function.
Convers a polyadic function into an unary function. E.g.
let f = |a, b, c| -> a + b + c
let g = unary(f)
g([1, 2, 3]) == 6
If the function already takes zero or one argument, it is returned unchanged.
This can be useful in HOF, for example to map
a binary function on a list of
couple:
let f = |a, b| -> ...
list[["a", 1], ["b", 2], ["c", 3]]: map(unary(f))
results in list[f("a", 1), f("b", 2), f("c", 3)]
The resulting unary function will accept any object having a toArray
method
(array, tuple, collection, map entry, struct…)
Thus, unary(func)(arg)
is equivalent to func: invoke(arg: toArray())
This function can also be used as a decorator.
Reverse of curry
.
Take a curried function (e.g. |a| -> |b| -> a + b
) and return a polyadic
function (e.g. |a, b| -> a + b
).
It is actually a variadic function calling the curried one in sequence.
The two functions defined by
let f = curry(|a, b, c| -> a + b + c)
let g = uncurry(|a| -> |b| -> |c| -> a + b + c)
have the same behavior.
This function can also be used as a decorator.
f
the function to uncurryf
See also curry
Apply the given function until the predicate holds.
For instance:
let f = until(gt(10), mul(2))
f(15) == 15
f(2) == 16
f(9) == 18
Convert an unary function taking an array into a variadic function.
This is the contrary of unary
.
E.g.
let f = |t| -> t:get(0) + t:get(1) + t:get(2)
let g = varargs(f)
f([1, 2, 3]) == g(1, 2, 3)
This function can also be used as a decorator.