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

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> 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?

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 (mentioned here)

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.

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

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.