FunctionChains.jl
FunctionChains.jl provides chained/composed functions with functionality beyond Base.ComposedFunction, as well as some other ways of combining functions.
The package defines the function fchain that turns a sequence of functions into a callable function chain. Functions are applied in the order they are given, so fchain(f, g, h) and fchain((f, g, h)) are semantically equivalent to h ∘ g ∘ f.
Function chains can be based on tuples of functions but also on arrays (e.g. fchain([x -> i * x for i in 1:4])) or generators/iterators (e.g. fchain((x -> i * x for i in 1:4))) of functions. fchain will always try to generate type-stable function chains if possible.
The function chain generated by fchain supports InverseFunctions.inverse, ChangesOfVariables.with_logabsdet_jacobian and Accessors.set, as well as the Adapt, Functors and FlexiMaps APIs, if all functions in the chain do support the respective functionality.
frepeat(f, n) and f∘̂ n build a chain of n repetitions of function f. Use fcomp(f, g, h) to compose functions in the order f ∘ g ∘ h, equivalent to fchain(h, g, f).
ffchain(f, g, h) and ffcomp(f, g, h) behave similar to fchain(f, g, h) and fcomp(f, g, h), but flatten and merge their arguments.
fcprod(fs) constructs a Cartesian product of functions. The resulting function supports InverseFunctions.inverse, ChangesOfVariables.with_logabsdet_jacobian, etc., similar to fchain, if all functions in the product do support the respective functionality.
FunctionChains also exports the convenience functions asfunction(f) and typed_callable(f) that wrap a callable f in a properly typed callable function (object) if necessary, e.g. if f is a type (constructor).
Function chains
Example:
using FunctionChains
f = fchain(Complex, sqrt)
f(-1)
# output
0.0 + 1.0img = fchain((x -> i * x for i in 1:4))
g(1.75)
# output
42.0The functions chains f and g in this example are both type stable
using Test
@inferred f(-1)@inferred g(1.75)In general, type stability will depend on the functions in the sequence and the type of the sequence itself.
Function products
A Cartesian product of functions applies some kind of collection (a tuple, array, NamedTuple or an iterable in general) of functions to a collection (with the same shape) of values, in an component/element-wise fashion:
fp = fcprod(x -> 2*x, x -> 3*x)
fp((4, 5))
# output
(8, 15)fp = fcprod((a = x -> 2*x, b = x -> 3*x))
fp((a = 4, b = 5))
# output
(a = 8, b = 15)Function fanouts
A function fanout applies some kind of collection a functions to single input, separately, resulting in a collection of the outputs:
fp = ffanout([Base.Fix1(*, 2), Base.Fix1(*, 3), Base.Fix1(*, 4)])
fp(4) == [8, 12, 16]
# output
truefp = ffanout((a = x -> 2*x, b = x -> 3*x))
fp(4)
# output
(a = 8, b = 12)