# More idiomatic way of phrasing \`reduce(\\circ, repeated(f, x))(y)\`?

**URL:** <https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647>\
**Category:** Performance\
**Tags:** performance, functional\
**Created:** [August 6, 2026, 3:01pm UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647 "2026-08-06T15:01:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 6, 2026, 3:01pm UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/1 "2026-08-06T15:01:49Z")

</div>

I usually use `reduce(∘, repeated(func, x))(a)` when I need to apply `func` to `a` `x` times, but apparently it spends most of the time creating the single composed function; averaging ~20x as long as an equivalent `accumulate` in this example despite not needing any allocs/gc:

```julia-auto
julia> f(a) = reduce(∘, repeated(exp, 1000))(a)
f (generic function with 1 method)

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max): 132.725 μs … 844.193 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 171.776 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 173.105 μs ± 40.335 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

      █▄ ▆
  ▂▂▁▂██▄▃▃▂▂▂█▆▅▄▂▂▂▂▂▂▂▂▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
  133 μs Histogram: frequency by time 331 μs <

 Memory estimate: 32 bytes, allocs estimate: 2.

julia> f(a) = accumulate((x,_)->exp(x), repeated(nothing, 1000); init=a)[end]
f (generic function with 1 method)

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 4 evaluations per sample.
 Range (min … max): 6.148 μs … 5.001 ms ┊ GC (min … max): 0.00% … 90.01%
 Time (median): 7.973 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 8.881 μs ± 49.997 μs ┊ GC (mean ± σ): 5.07% ± 0.90%

  ▂ ▇▅▄▄▃▆█▆▆▄█▆▄▃▂▂▂▁▂▁▁▁▂▁▁ ▂
  █▇▇▇▄███████████████████████████████▇██▇▇▇▇▆▅▆▆▆▆▆▆▅▆▅▆▄▄▄ █
  6.15 μs Histogram: log(frequency) by time 14.9 μs <

 Memory estimate: 7.85 KiB, allocs estimate: 2.

```

is there a way to tell julia to just apply the functions directly instead of first collecting them into a composed function?

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 6, 2026, 3:13pm UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/2 "2026-08-06T15:13:32Z")

</div>

of course the magic related section is better at searching than the search bar or the related posts that pop up when composing a thread.

[from here](https://discourse.julialang.org/t/seven-lines-of-julia-examples-sought/50416/81) (mentioned [here](https://discourse.julialang.org/t/recursively-applied-1d-function/67602/4))

```julia-auto
julia> f(a) = foldl((x,_) -> exp(x), repeated(nothing, 1000); init=a)
f (generic function with 1 method)

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 8.146 ns … 25.388 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 8.871 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 8.995 ns ± 1.472 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▄ ▅█▂ ▃ ▁
  ██▇▆▇█████▇▇▆▆▆▆▆▆▆▆▆▆▅▆▆▆▅▆▆▅▆▇▅▇▇▆▆▇▆▇▇▇▅▆▇▆▇▆▇▇▇▆▇▇▇▇▆▆ █
  8.15 ns Histogram: log(frequency) by time 15.2 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [August 6, 2026, 3:21pm UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/3 "2026-08-06T15:21:15Z")

</div>

Yeah, I was going to suggest the `foldl` approach, but you might also be interested in the `iterated` iterator from IterTools.jl.

```julia-repl
julia> using IterTools

help?> iterated
search: iterated iterate @generated Iterators issorted insorted inertia interleaveby ismarked

  iterated(f, x)

  Iterate over successive applications of f, as in x, f(x), f(f(x)), f(f(f(x))), ...

  Use Base.Iterators.take() to obtain the required number of elements.

  julia> for i in Iterators.take(iterated(x -> 2x, 1), 5)
             @show i
         end
  i = 1
  i = 2
  i = 4
  i = 8
  i = 16
  
  julia> for i in Iterators.take(iterated(sqrt, 100), 6)
             @show i
         end
  i = 100
  i = 10.0
  i = 3.1622776601683795
  i = 1.7782794100389228
  i = 1.333521432163324
  i = 1.1547819846894583

```

This thing probably isn’t as performant as your `foldl` loop though.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [August 7, 2026, 3:50am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/4 "2026-08-07T03:50:02Z")

</div>

```julia-auto
julia> using FunctionChains: ∘̂

julia> 1 |> exp ∘̂ 3
3.814279104760214e6

```

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 4:52am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/5 "2026-08-07T04:52:30Z")

</div>

looks like it’s about as fast as `accumulate` but without allocations. not as impressive as the `foldl` method, but uses less unnecessary letters:

```julia-auto
julia> f(a) = a |> exp ∘̂ 1000
f (generic function with 1 method)

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 6.468 μs … 18.651 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.532 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 6.661 μs ± 637.748 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  ██▂ ▁
  ████▇█▇▇▆▆▆▆▇█████▆▇▆▆▆▆▆▅▅▆▅▆▅▅▆▆▅▆▅▅▆▅▅▅▃▅▅▃▅▅▅▆▆▃▅▃▄▅▃▅▄ █
  6.47 μs Histogram: log(frequency) by time 9.53 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

looks like a just a straight up better version of `reduce(∘, repeated(f, x))`, since it exposes a handle to the composed function as well. maybe the function in base could be optimized better?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 7, 2026, 5:45am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/6 "2026-08-07T05:45:36Z")

</div>

> [@rokke](#):
>
> ```julia-auto
> julia> @benchmark f(10.)
> BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
> Range (min … max): 8.146 ns … 25.388 ns ┊ GC (min … max): 0.00% … 0.00%
> Time (median): 8.871 ns ┊ GC (median): 0.00%
> 
> ```

1000 applications of `exp` in 8ns, does that seem reasonable to you? I would expect one _single_ `exp` call to take close to that long.

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 6:06am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/7 "2026-08-07T06:06:52Z")

</div>

huh, yeah. that is weird. think I was on master instead of release; going back to release goes back to μs range

```julia-auto
julia> f(a) = foldl((x,_) -> exp(x), repeated(nothing, 1000); init=a)
f (generic function with 1 method)

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.775 μs … 60.120 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.536 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 7.309 μs ± 1.955 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▁ █▃▁▁▁ ▁▁ ▄▄ ▄ ▃ ▁
  █▅▁▃▁▃█████▇▇██▇▇▇█████████▇▇▇▇▇█▇▇▆▆▇▆▇▇▆▆▅▆▅▅▄▅▄▅▅▄▅▅█▅▅ █
  5.78 μs Histogram: log(frequency) by time 12.3 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

maybe master decided to start memorizing? the majority of calls will be `exp(Inf) = Inf`, and one `exp()` is only about `2 ns`, so it’s possible that it realized we weren’t using the second argument and just returned the repeated value. using 10 instead of 1000 takes about the same time on master

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 6:20am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/8 "2026-08-07T06:20:08Z")

</div>

it was compilation:

```julia-auto
julia> @benchmark f($10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.783 μs … 48.659 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.544 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 6.853 μs ± 1.082 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

         ▇█▂▁ ▁
  ▅▁▁▁▃▁▁█████████▇▇█▇▇███████▇█▇▇███████▇███▇▇▇▆▆▆▅▆▆▆▅▅▆▄▄ █
  5.78 μs Histogram: log(frequency) by time 11.1 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 8.876 ns … 22.079 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 8.968 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 9.595 ns ± 1.171 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▆ ▁▁ ▂▂ ▆▅ ▂
  ███▅▆▁██▄▅▅▅▆██▅▄▅▅▅▇███▆▅▅▅▅▆█▆▄▅▅▆▅▇▅▅▅▅▆▆▅▆▅▅▅▅▅▅▄▅▃▁▅▅ █
  8.88 ns Histogram: log(frequency) by time 14.2 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

(as stated here):

```julia-auto
function _foldl_impl(op::OP, init, itr) where {OP}
    # Unroll the loop once to check if the iterator is empty.
    # If init is known, the call to op may be evaluated at compile time
    y = iterate(itr)
    y === nothing && return init
    v = op(init, y[1])
    # Using a for loop is more performant than a while loop (see #56492)
    # This unrolls the loop a second time before entering the body
    for x in Iterators.rest(itr, y[2])
        v = op(v, x)
    end
    return v
end

```

---

<div class="post-metadata">

**Author:** ![BjarkeHautop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarkehautop/32/219291_2.png) [@BjarkeHautop](https://discourse.julialang.org/u/BjarkeHautop)\
**Post date:** [August 7, 2026, 6:31am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/9 "2026-08-07T06:31:41Z")

</div>

Here are my results of the four method discussed in this thread:

```julia
using BenchmarkTools, Base.Iterators, IterTools

f1(a) = reduce(∘, repeated(exp, 1000))(a)
f2(a) = accumulate((x, _) -> exp(x), repeated(nothing, 1000); init=a)[end]
f3(a) = foldl((x, _) -> exp(x), repeated(nothing, 1000); init=a)
f4(a) = first(Iterators.drop(iterated(exp, a), 1000))

# Warmup + assert equal
@assert f1(10.0) == f2(10.0) == f3(10.0) == f4(10.0)

show(stdout, MIME("text/plain"), @benchmark f1(10.0)); println()
#> BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
#> Range (min … max): 55.516 μs … 555.481 μs ┊ GC (min … max): 0.00% … 0.00%
#> Time (median): 58.083 μs ┊ GC (median): 0.00%
#> Time (mean ± σ): 59.279 μs ± 14.249 μs ┊ GC (mean ± σ): 0.00% ± 0.00%
#> 
#> █▇▄▃▁ ▁                                                  
#> ▁▁▂▇█████▇▇██▆▆▆▄▃▄▄▂▂▂▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
#> 55.5 μs Histogram: frequency by time 73 μs <
#> 
#> Memory estimate: 32 bytes, allocs estimate: 2.
show(stdout, MIME("text/plain"), @benchmark f2(10.0)); println()
#> BenchmarkTools.Trial: 10000 samples with 9 evaluations per sample.
#> Range (min … max): 2.139 μs … 32.680 μs ┊ GC (min … max): 0.00% … 78.02%
#> Time (median): 2.208 μs ┊ GC (median): 0.00%
#> Time (mean ± σ): 2.377 μs ± 1.676 μs ┊ GC (mean ± σ): 5.19% ± 6.65%
#> 
#> ▅██▆▃ ▁▁ ▂
#> █████▇▆▇▆▇▆▆▆▆████▇▆▆▆▆▆▅▅▃▄▁▃▁▁▃▃▃▁▁▄▁▄▁▃▃▁▃▄▁▁▁▁▁▁▁▃▁▁▁▃ █
#> 2.14 μs Histogram: log(frequency) by time 4.06 μs <
#> 
#> Memory estimate: 7.88 KiB, allocs estimate: 3.
show(stdout, MIME("text/plain"), @benchmark f3(10.0)); println()
#> BenchmarkTools.Trial: 10000 samples with 9 evaluations per sample.
#> Range (min … max): 2.071 μs … 21.754 μs ┊ GC (min … max): 0.00% … 0.00%
#> Time (median): 2.073 μs ┊ GC (median): 0.00%
#> Time (mean ± σ): 2.122 μs ± 534.683 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
#> 
#> █ ▃ ▃▂▄ ▄ ▄ ▂ ▁
#> ███▅▃▁▁▃▁▁▁▆█████▄█▃█▃█▁▃▃▄▃▄▁▃▁▁▁▁▁▁▁▄▁▁▃▁▁▅▃▆▆▆▆▆▅▅▃▄▄▅▆▆ █
#> 2.07 μs Histogram: log(frequency) by time 2.43 μs <
#> 
#> Memory estimate: 0 bytes, allocs estimate: 0.
show(stdout, MIME("text/plain"), @benchmark f4(10.0)); println()
#> BenchmarkTools.Trial: 10000 samples with 9 evaluations per sample.
#> Range (min … max): 2.110 μs … 4.229 μs ┊ GC (min … max): 0.00% … 0.00%
#> Time (median): 2.123 μs ┊ GC (median): 0.00%
#> Time (mean ± σ): 2.146 μs ± 164.411 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
#> 
#> █                                                           
#> ▆█▃▄▂▁▁▂▂▂▂▂▁▁▁▁▁▂▁▁▁▁▂▂▂▁▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▂
#> 2.11 μs Histogram: frequency by time 2.59 μs <
#> 
#> Memory estimate: 0 bytes, allocs estimate: 0.

```

Created on 2026-08-07 with [MinimalWorkingExamples v1.0.0](https://github.com/BjarkeHautop/MinimalWorkingExamples.jl) using Julia 1.12.6

> **Environment**
>
> ```plaintext
> Julia Version 1.12.6
> Commit 15346901f00 (2026-04-09 19:20 UTC)
> Build Info:
> Official https://julialang.org release
> Platform Info:
> OS: Linux (x86_64-linux-gnu)
> CPU: 16 × AMD Ryzen 7 8845HS w/ Radeon 780M Graphics
> WORD_SIZE: 64
> LLVM: libLLVM-18.1.7 (ORCJIT, znver3)
> GC: Built with stock GC
> Threads: 1 default, 1 interactive, 1 GC (on 16 virtual cores)
> Environment:
> JULIA_LOAD_PATH = @:@stdlib
> 
> ```

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 6:38am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/10 "2026-08-07T06:38:50Z")

</div>

here’s master with those same functions:

```julia-auto
julia> show(stdout, MIME("text/plain"), @benchmark f1($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max): 154.901 μs … 1.272 ms ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 166.506 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 174.343 μs ± 26.890 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

      ▃█▇▄▂▃▃▃▃▃▄▃▃▂▂▁▁▁▁ ▁
  ▅▅▂▄██████████████████████▇▇▇▆▆▇▆▆▆▆▅▆▆▆▄▆▅▅▅▂▅▃▄▅▅▅▂▂▄▄▃▄▂▅ █
  155 μs Histogram: log(frequency) by time 266 μs <

 Memory estimate: 32 bytes, allocs estimate: 2.

julia> show(stdout, MIME("text/plain"), @benchmark f2($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 4 evaluations per sample.
 Range (min … max): 6.750 μs … 422.931 μs ┊ GC (min … max): 0.00% … 94.64%
 Time (median): 7.289 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 8.438 μs ± 16.250 μs ┊ GC (mean ± σ): 7.69% ± 3.94%

    ▇██▇▅▄▃▂▂▁▁▁▁▁ ▂
  ▄▂███████████████████████████▇████▇▇█▆█▇▆▇▆▅▆▆▆▄▆▅▄▅▅▄▃▄▄▄▅ █
  6.75 μs Histogram: log(frequency) by time 13.9 μs <

 Memory estimate: 7.88 KiB, allocs estimate: 3.

julia> show(stdout, MIME("text/plain"), @benchmark f3($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.783 μs … 62.308 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.863 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 7.457 μs ± 1.904 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▁ █▇▃▁▂ ▂█▁ ▄▁▁▁▁▁ ▁ ▁ ▁ ▄▁ ▂
  █▅▁▅▄██████▇████▇█████████████████▆█▇▇▇▇▆▆▆▇▆▅▆▆▅▆▅██▆▆▆▆▆ █
  5.78 μs Histogram: log(frequency) by time 12.8 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> show(stdout, MIME("text/plain"), @benchmark f4($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.784 μs … 29.078 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.548 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 6.780 μs ± 913.185 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▁ ██▂▁▁ ▁▁ ▂
  █▄▁▁▄▃▁▃█████████████▇█▇███▇▇▇▇▇▇▇▇▇▇▇▇▇█▆▇▇█▇▇▆▇▇▆▇▇▅▆▆▅▄▆ █
  5.78 μs Histogram: log(frequency) by time 10.7 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> #now let them compile everything away by removing the $

julia> show(stdout, MIME("text/plain"), @benchmark f1(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max): 162.456 μs … 586.251 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 166.788 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 178.351 μs ± 25.721 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▄█▇▄▄▄▃▃▃▂▂▂▃▃▁▁▁▁▁▁ ▂▃▁ ▁ ▁▂▁ ▂
  ██████████████████████████████▇▇▇▇▆▇▆▇▆▇▆▆▅▇█████▇▇▇▆▅▆▅▅▅▂▄▄ █
  162 μs Histogram: log(frequency) by time 263 μs <

 Memory estimate: 32 bytes, allocs estimate: 2.

julia> show(stdout, MIME("text/plain"), @benchmark f2(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 6.937 μs … 776.736 μs ┊ GC (min … max): 0.00% … 87.47%
 Time (median): 7.812 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 9.227 μs ± 19.372 μs ┊ GC (mean ± σ): 8.45% ± 4.15%

  ▇█▇▅▄▅▆▆▅▄▄▃▂▂▂▂▂▁▁▁▁▁ ▁ ▁▁ ▁▁▂▂▁ ▂
  ███████████████████████████████▇▇▇▆▆▆██████▇▆▇▇▆▇▆▆▆▆▆▅▅▅▄▅ █
  6.94 μs Histogram: log(frequency) by time 16.2 μs <

 Memory estimate: 7.85 KiB, allocs estimate: 2.

julia> show(stdout, MIME("text/plain"), @benchmark f3(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 9.012 ns … 128.866 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 9.093 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 9.759 ns ± 2.875 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▅▂▁ ▃ ▃▁ ▁▂ ▂▅▃ ▁
  ████▇█▆▆▆▄██▅▃▃▄██▁▅▄▄▁████▇▅▅▅▄▄▅▅▅▁▄▅▅▅▅▅▃▄▄▄▄▄▃▄▄▃▄▄▄▁▄▄ █
  9.01 ns Histogram: log(frequency) by time 15.5 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> show(stdout, MIME("text/plain"), @benchmark f4(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 8.841 ns … 114.111 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 9.141 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 9.885 ns ± 2.716 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▇█▃▂ ▃ ▆▅▂ ▂
  ██████████▇▇▆██▇▇▆██████▇▇▇▆▆▆▇▅▆▅▅▅▇▆▆▆▆▆▅▆▆▆▅▆▆▅▄▁▆▅▅▅▆▄▆ █
  8.84 ns Histogram: log(frequency) by time 17.4 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

here’s the above again, with release on the same computer:

```julia-auto
julia> show(stdout, MIME("text/plain"), @benchmark f1($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max): 160.846 μs … 742.954 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 173.678 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 190.036 μs ± 35.612 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▆█▇▅▄▃▃▂▃▄▅▃▃▂▃▄▄▂▂▂▁▁▂▁▁▁▁ ▁ ▃▄▃▂▂▁ ▁ ▂
  ██████████████████████████████████████▇█▇▇▆▆▅▆▅▅▄▃▄▄▄▃▅▅▅██▄▆ █
  161 μs Histogram: log(frequency) by time 311 μs <

 Memory estimate: 32 bytes, allocs estimate: 2.

julia> show(stdout, MIME("text/plain"), @benchmark f2($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 4 evaluations per sample.
 Range (min … max): 7.054 μs … 645.076 μs ┊ GC (min … max): 0.00% … 81.21%
 Time (median): 8.277 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 9.690 μs ± 24.047 μs ┊ GC (mean ± σ): 9.79% ± 4.01%

  ▂▄▅▃▂▂▂▂▄▇█▇▅▃▃▄▃▂▂▁▂▁▁▁▁ ▁▂▂ ▂
  █████████████████████████████████▇▇▇▇▇▇▇▇▆▆▅▅▆▅▅▅▅▅▅▅▄▂▄▅▄▄ █
  7.05 μs Histogram: log(frequency) by time 13.8 μs <

 Memory estimate: 7.88 KiB, allocs estimate: 3.

julia> show(stdout, MIME("text/plain"), @benchmark f3($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.780 μs … 99.489 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.541 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 6.771 μs ± 1.322 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

        ▆█▃▁ ▁▁ ▁
  █▄▃▁▄▃████▇██████▇▇▇▇▇▇▇▆▇▆▇▇▇▇▅▇█▇▇▆▆▆▆▆▆▆▆▄▆▆▅▆▅▄▅▆▃▅▅▆▆ █
  5.78 μs Histogram: log(frequency) by time 11.7 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> show(stdout, MIME("text/plain"), @benchmark f4($10.0)); println()
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.787 μs … 36.082 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.555 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 6.893 μs ± 1.067 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

         █▄▂▁ ▁ ▁
  ▄▃▁▁▁▃▆███████▇██▇▇█████▇██▇███████▇██▇▇▇▆▆▆▆▇▇▅▆▅▆▇▅▅▅▆▆▅ █
  5.79 μs Histogram: log(frequency) by time 11.5 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> # now without the $ for full compilation magic

julia> show(stdout, MIME("text/plain"), @benchmark f1(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max): 160.282 μs … 2.132 ms ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 169.225 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 180.205 μs ± 41.184 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▆█▆▄▄▃▃▃▃▅▆▅▄▃▂▂▁▁▁ ▁ ▂
  ██████████████████████▇▇▆█▇▆▆▇▇██▇▇▆▆▅▆▅▄▅▅▄▆▅▄▄▄▄▆▃▅▃▄▂▂▄▆▆ █
  160 μs Histogram: log(frequency) by time 307 μs <

 Memory estimate: 32 bytes, allocs estimate: 2.

julia> show(stdout, MIME("text/plain"), @benchmark f2(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 4 evaluations per sample.
 Range (min … max): 6.568 μs … 639.685 μs ┊ GC (min … max): 0.00% … 83.01%
 Time (median): 7.432 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 9.166 μs ± 18.370 μs ┊ GC (mean ± σ): 8.23% ± 4.27%

     ▆█▇▄▃▃▁▃▂▁▄▅▄▂▂▃▂▁ ▁▃▄▃▁ ▂
  ▄▄▁██████████████████████████████▇▇█▇▆▇▇▆▆▅▆▅▆▅▅▄▅▄▄▄▄▄▄▄▄▅ █
  6.57 μs Histogram: log(frequency) by time 15.9 μs <

 Memory estimate: 7.88 KiB, allocs estimate: 3.

julia> show(stdout, MIME("text/plain"), @benchmark f3(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 6 evaluations per sample.
 Range (min … max): 5.780 μs … 174.387 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.538 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 7.630 μs ± 2.717 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

       █▅▂▁▁▁▁▁ ▁ ▂ ▁ ▃ ▂▅ ▁
  ▅▁▁▁▃██████████████████████████████▇▇▇▇▆▆▇▆▆▆▅▅▅██▆▆▅▆▄▄▆▅▇ █
  5.78 μs Histogram: log(frequency) by time 13.3 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> show(stdout, MIME("text/plain"), @benchmark f4(10.0)); println()
BenchmarkTools.Trial: 10000 samples with 6 evaluations per sample.
 Range (min … max): 5.836 μs … 39.879 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 6.549 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 6.889 μs ± 1.223 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

        █▃▁ ▁▁▁▂ ▂ ▁
  ▃▁▁▁▁████████████▇██▇▇▇▆▇▇▇▇▇▇▇▇▇██▆▆▆▆▆▅▆▆▅▅▆▅▅▅▅▅▅▅▅▄▅▄▇ █
  5.84 μs Histogram: log(frequency) by time 12.1 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 7, 2026, 7:08am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/11 "2026-08-07T07:08:29Z")

</div>

You should also try with just a simple loop (wrapped in a function, of course).

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 7:12am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/12 "2026-08-07T07:12:24Z")

</div>

I don’t think there’s going to be any way to beat the compiler optimizing the entire loop away

(on release):

```julia-auto
julia> f(a) = (for _=1:1000 a=exp(a) end; a)
f (generic function with 1 method)

julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 5.788 μs … 221.824 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 7.374 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 7.333 μs ± 2.458 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▁ ▆▇▂ ▁█▂▁ ▁ ▂ ▂ ▁▂ ▁ ▂
  █▇▅▁▁▄▃▃████▇▆▄▅▅▃█████▇███▇▇███▇█▇▇██▇▇▇██▇█▇▆▆▇▆▆▄▆▆▃▄▅▄▄ █
  5.79 μs Histogram: log(frequency) by time 10.7 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 7, 2026, 7:27am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/13 "2026-08-07T07:27:12Z")

</div>

> [@rokke](#):
>
> I don’t think there’s going to be any way to beat the compiler optimizing the entire loop away

Sure, but that’s not happening in reality, is it? You do not know what value that you will call `f` with in any non-trivial case. And any way, the same optimization should probably happen with the simple loop as well. If it doesn’t, that deserves some investigation.

When benchmarking stuff like this, I would always recommend comparing with a baseline loop (which is normally also the optimal solution).

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 7:35am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/14 "2026-08-07T07:35:18Z")

</div>

I think `foldl` may be able to guarantee its function will not change for each iteration of the loop, while a simple for loop may run something different each time. I wouldn’t be surprised if `foldl` was able to compile itself down to nothing better than an equivalent for loop, since it has `op` in the call signature: `_foldl_impl(op::OP, init, itr) where {OP}`.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 7, 2026, 7:40am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/15 "2026-08-07T07:40:12Z")

</div>

You can do the same thing yourself with a simple loop.

> [@rokke](#):
>
> I wouldn’t be surprised if `foldl` was able to compile itself down to nothing better than an equivalent for loop

Exactly.

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 8:24am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/16 "2026-08-07T08:24:47Z")

</div>

I stand corrected. apparently it can compile the for loop away as well:

```julia-auto
julia> f1(a) = foldl((x,_) -> exp(x), repeated(nothing, 1000); init=a)
f1 (generic function with 1 method)

julia> f2(a) = (for _=1:1000 a=exp(a) end; a)
f2 (generic function with 1 method)

julia> @benchmark f1(10.)
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 8.914 ns … 215.865 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 9.201 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 9.477 ns ± 3.195 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▇▄█▄▂▄▂ ▃▂ ▂▃ ▂
  ████████▇█▇▇████▆▆▇████▇▇▇▅▆▅█▇▆▆▆▆▅▅▅▆▅▆▅▅▄▆▃▆▅▅▅▆▄▁▅▅▅▄▅▅ █
  8.91 ns Histogram: log(frequency) by time 14.7 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark f2(10.)
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 8.915 ns … 143.037 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 9.076 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 9.862 ns ± 2.721 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  ██▂▆▂▂▃ ▂▂ ▇▆▄ ▂
  ████████▆▇▆▇███▆▆▆▆█████▆▇▇▆▆▅▄▆▅▅▅▆▅▄▄▄▅▄▅▅▅▅▄▄▄▅▄▄▄▄▄▅▅▅▃ █
  8.91 ns Histogram: log(frequency) by time 14.9 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

(sorry for the long gap between replies; I had just started rebuilding a new master…)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 7, 2026, 8:55am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/17 "2026-08-07T08:55:51Z")

</div>

I think it’s fantastic how these functional patterns can be efficiently implemented with with pretty simple Julia code. But it also highlights how “just roll your own simple loop implementation” is so frequently a viable strategy in Julia.

> [@rokke](#):
>
> sorry for the long gap between replies

Not at all, I’m much slower​😁

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [August 7, 2026, 10:54am UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/18 "2026-08-07T10:54:34Z")

</div>

Is the ability to hoist away the loop the part you actually intend to benchmark here though? The loop is only removable when the argument is a constant.

Keep in mind, this is only possible because of the way you’ve benchmarked it, where the argument `10.0` is a compile-time constant, so it just hoists the evaluations out of the loop. If you care about how long it takes to actually compute this though, you’ll likely need to make it so that the compiler can’t infer `10.0` as a constant. E.g.

```julia-auto
julia> let x = Ref(10.0)
           @benchmark f1($x[])
       end
BenchmarkTools.Trial: 10000 samples with 10 evaluations per sample.
 Range (min … max): 2.231 μs … 4.530 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 2.260 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 2.268 μs ± 70.451 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

     ▂█▆                                                      
  ▂▃▆████▅▃▃▃▂▂▂▁▂▁▂▁▁▂▁▁▂▁▂▂▁▁▂▁▁▁▁▁▁▁▂▂▁▁▁▁▁▂▁▂▁▂▁▁▂▂▂▂▂▂▂ ▃
  2.23 μs Histogram: frequency by time 2.57 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> let x = Ref(10.0)
           @benchmark f2($x[])
       end
BenchmarkTools.Trial: 10000 samples with 10 evaluations per sample.
 Range (min … max): 2.107 μs … 6.654 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 2.266 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 2.294 μs ± 190.517 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▂ ▁ ▄▇█▆▃▁ ▂
  ███▁███████▅▅▅▅▅▄▅▅▅▇▆▆▇▆█▇▄▅▅▄▄▅▅▅▆▃▄▄▅▄▁▁▃▃▁▄▄▄▅▄▄▃▁▄▁▄▃▇ █
  2.11 μs Histogram: log(frequency) by time 3.41 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![rokke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rokke/32/222691_2.png) [@rokke](https://discourse.julialang.org/u/rokke)\
**Post date:** [August 7, 2026, 12:04pm UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/19 "2026-08-07T12:04:37Z")

</div>

the compiler will propagate some constants for you, so there are some cases it gets completely taken care of beforehand

```julia-auto
julia> f(a, b, c) = (k=1000+b; foldl((x,_) -> exp(x), repeated(nothing, k-b); init=a+c))
f (generic function with 2 methods)

julia> @benchmark f(10., 10, 0.)
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
 Range (min … max): 8.298 ns … 692.584 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 10.393 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 10.740 ns ± 7.561 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

      ▅▇▇▄▃▂▅▁ ▅▄▂▁▂▅▂▁ ▃█▄▂ ▂
  █▃▁▁████████▇▇██████████████▇▇█▆▇▇▆▅▇▇▇▆▅▅▅▄▆▆▆▆▅▅▄▃▅▅▄▅▄▄▃▃ █
  8.3 ns Histogram: log(frequency) by time 16.8 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

also you can put `$` directly on a value and it’ll still hide it for you:

```julia-auto
julia> @benchmark f($10., 10, 0.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
 Range (min … max): 6.573 μs … 86.563 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 7.549 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 8.105 μs ± 2.508 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▁ ▁ █▄▁▂▅▂▁▁▁▁ ▃ ▁
  █▃▂█▇▅████████████▇▇▇██▇▆▆▆▆▆▆▅▅▆▆▅▅▅▆▄▄▅▅▄▅▄▅▆▅▅▅▅▅▄▃▄▃▃▄ █
  6.57 μs Histogram: log(frequency) by time 14.8 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [August 7, 2026, 1:32pm UTC](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647/20 "2026-08-07T13:32:31Z")

</div>

Maybe `Core.donotdelete` might come in handy?

[Next page](https://discourse.julialang.org/t/more-idiomatic-way-of-phrasing-reduce-circ-repeated-f-x-y/138647.md?page=2)
