# Chaining array of functions

**URL:** <https://discourse.julialang.org/t/chaining-array-of-functions/30958>\
**Category:** General Usage\
**Created:** [November 11, 2019, 3:09pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958 "2019-11-11T15:09:16Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![DR59](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dr59/32/10087_2.png) [@DR59](https://discourse.julialang.org/u/DR59)\
**Post date:** [November 11, 2019, 3:09pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/1 "2019-11-11T15:09:16Z")

</div>

Suppose I have a 1d array of functions:  
f\_array = [f1, f2, f3, f4]

This array can be of arbitrary length, and each function may have multiple inputs/outputs.

How do I do a reduce style operation to make a new function consisting of the composition of all previous functions: So an f satisfying  
f(x) = f1 o f2 o f3 o f4(x)

Can’t work it out. Thanks!!!

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [November 11, 2019, 3:19pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/2 "2019-11-11T15:19:49Z")

</div>

```nohighlight
f1(x) = x^1
f2(x) = x^2
f3(x) = x^3
f4(x) = x^4
f(x) = (f1∘f2∘f3∘f4)(x)

```

---

<div class="post-metadata">

**Author:** ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)\
**Post date:** [November 11, 2019, 3:20pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/3 "2019-11-11T15:20:42Z")

</div>

You can do  
`reduce(∘, f_array)(x)`

Note that functions in containers in Julia are not automatically very efficient, usually there is an expensive unboxing step that needs to take place.

Consider checking out [FunctionWrappers.jl](https://github.com/yuyichao/FunctionWrappers.jl) (fortunately this still works even on Julia 1.3).

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [November 11, 2019, 3:28pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/4 "2019-11-11T15:28:30Z")

</div>

You might want `foldl()` or `foldr()` instead of `reduce`, since `reduce` does not make any guarantees about its associativity.

It’s also worth noting that you actually get good performance using the chained function without needing to use FunctionWrappers or anything like it:

```julia
julia> f1(x) = x^1
f1 (generic function with 1 method)

julia> f2(x) = x^2
f2 (generic function with 1 method)

julia> f3(x) = x^3
f3 (generic function with 1 method)

julia> f4(x) = x^4
f4 (generic function with 1 method)

julia> f = foldl(∘, [f1, f2, f3, f4])
#58 (generic function with 1 method)

julia> using BenchmarkTools

julia> @btime $f($(1.0))
  21.348 ns (0 allocations: 0 bytes)
1.0

```

What’s happening here is that the return type of `foldl` itself cannot be inferred (because it depends on the non-concrete element types of `[f1, f2, f3, f4]`, but the _resulting function_ that it returns has no such limitations:

```julia
julia> @code_warntype foldl(∘, [f1, f2, f3, f4])
Variables
  #self#::Core.Compiler.Const(foldl, false)
  op::Core.Compiler.Const(∘, false)
  itr::Array{Function,1}

Body::Any
1 ─ %1 = Core.NamedTuple()::Core.Compiler.Const(NamedTuple(), false)
│ %2 = Base.pairs(%1)::Core.Compiler.Const(Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}(), false)
│ %3 = Base.:(#foldl#189)(%2, #self#, op, itr)::Any
└── return %3

julia> @code_warntype f(1.0)
Variables
  #self#::Core.Compiler.Const(getfield(Base, Symbol("##58#59")){getfield(Base, Symbol("##58#59")){getfield(Base, Symbol("##58#59")){typeof(f1),typeof(f2)},typeof(f3)},typeof(f4)}(getfield(Base, Symbol("##58#59")){getfield(Base, Symbol("##58#59")){typeof(f1),typeof(f2)},typeof(f3)}(getfield(Base, Symbol("##58#59")){typeof(f1),typeof(f2)}(f1, f2), f3), f4), false)
  x::Tuple{Float64}

Body::Float64
1 ─ %1 = Core.getfield(#self#, :f)::Core.Compiler.Const(getfield(Base, Symbol("##58#59")){getfield(Base, Symbol("##58#59")){typeof(f1),typeof(f2)},typeof(f3)}(getfield(Base, Symbol("##58#59")){typeof(f1),typeof(f2)}(f1, f2), f3), false)
│ %2 = Core.getfield(#self#, :g)::Core.Compiler.Const(f4, false)
│ %3 = Core._apply(%2, x)::Float64
│ %4 = (%1)(%3)::Float64
└── return %4

```

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [November 11, 2019, 4:29pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/5 "2019-11-11T16:29:20Z")

</div>

In Julia 1.4, you can use `∘(f_array...)`: [https://docs.julialang.org/en/latest/base/base/#Base.:∘](https://docs.julialang.org/en/latest/base/base/#Base.:%E2%88%98)

> [@rdeits](#):
>
> You might want `foldl()` or `foldr()` instead of `reduce` , since `reduce` does not make any guarantees about its associativity.

As `∘` is associative, this doesn’t matter much. But I agree using `foldl` here is nicer.

Also, if you want to support arbitrary length array, including empty one, it’s important to specify `init` as in `foldl(∘, f_array; init=identity)`.

---

<div class="post-metadata">

**Author:** ![DR59](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dr59/32/10087_2.png) [@DR59](https://discourse.julialang.org/u/DR59)\
**Post date:** [November 11, 2019, 6:02pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/6 "2019-11-11T18:02:38Z")

</div>

Thanks a lot everybody, every single answer was really helpful.

I edited this post: somehow in my head I mixed associativity and commutativity and wrote something that would be confusing for readers based on that. Not great for a supposed mathematician, I’ll blame it on jetlag!

To correctly (this time) summarise the above: reduce() requires associativity of the operator it is reducing with respect to. Therefore it is OK for function composition, which is associative. foldl() and foldr() additionally work on non-associative operations, as they fix the order in which the computer carries the reduction.

Thanks again for the prompt, informative replies! I’m not someone who has really posted on forums of any kind much before, was pleasantly surprised :).

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [November 11, 2019, 6:51pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/7 "2019-11-11T18:51:29Z")

</div>

Aren’t you mixing [associativity](https://en.wikipedia.org/wiki/Associative_property) and [commutativity](https://en.wikipedia.org/wiki/Commutative_property)? Note that `reduce` requires associativity but _not_ commutativity. So `reduce` _does_ give you the correct result for `∘`.

---

<div class="post-metadata">

**Author:** ![DR59](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dr59/32/10087_2.png) [@DR59](https://discourse.julialang.org/u/DR59)\
**Post date:** [November 11, 2019, 7:29pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/8 "2019-11-11T19:29:27Z")

</div>

Hi tkf,

Yes I was! Thanks. I actually was trying to say composition is not commutative but is associative, I got the words jumbled. I was actually misunderstanding the reduce() function, which I see operates on associative operations regardless of commutativity, and is therefore amenable to the composition operator.

Thanks 🙂 I’ll edit my previous post to reflect that

---

<div class="post-metadata">

**Author:** ![anon92994695](https://avatars.discourse-cdn.com/v4/letter/a/ce7236/32.png) [@anon92994695](https://discourse.julialang.org/u/anon92994695)\
**Post date:** [November 11, 2019, 11:16pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/9 "2019-11-11T23:16:30Z")

</div>

I have some examples of doing this in my package with what I call “pipelines”

> <https://github.com/caseykneale/ChemometricsTools.jl/blob/master/src/Transformations.jl>

Maybe it’ll help give you ideas.

---

<div class="post-metadata">

**Author:** ![DR59](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dr59/32/10087_2.png) [@DR59](https://discourse.julialang.org/u/DR59)\
**Post date:** [November 12, 2019, 4:03pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/10 "2019-11-12T16:03:30Z")

</div>

Perfect, it’s a superset of what I wanted to do. Thanks!

---

<div class="post-metadata">

**Author:** ![anon92994695](https://avatars.discourse-cdn.com/v4/letter/a/ce7236/32.png) [@anon92994695](https://discourse.julialang.org/u/anon92994695)\
**Post date:** [November 12, 2019, 9:51pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/11 "2019-11-12T21:51:37Z")

</div>

If you find any cool or better patterns please report back! I’d love to improve whats being done there. By the way that code is MIT licensed so do whatever you please with it.

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 10, 2021, 11:11am UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/12 "2021-05-10T11:11:33Z")

</div>

> [@tkf](#):
>
> ∘(f\_array…)

Composition on a tuplet works as you suggest, but composition on an array does something else, am I understanding correctly?

### composition on a tuplet:

```
julia> ∘(f1, f2, f3)
f1 ∘ f2 ∘ f3

```

### composition on an array

```
julia> ∘([f1, f2, f3])
3-element Vector{Function}:
f1 (generic function with 1 method)
f2 (generic function with 1 method)
f3 (generic function with 1 method)

```

Thanks!

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [May 10, 2021, 11:37am UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/13 "2021-05-10T11:37:20Z")

</div>

You want to splat here:

```julia
julia> ∘([f1, f2, f3]...)
f1 ∘ f2 ∘ f3

```

otherwise you’re only passing one argument (the array) to `∘`

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 10, 2021, 12:02pm UTC](https://discourse.julialang.org/t/chaining-array-of-functions/30958/14 "2021-05-10T12:02:39Z")

</div>

Oh of course, thanks a lot Nils!
