piever
August 7, 2026, 1:33pm
21
rokke:
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; […] is there a way to tell julia to just apply the functions directly instead of first collecting them into a composed function?
A bit late to the party, but the closest thing to what you are doing is to use foldl with |> instead of creating the composite function. For instance
val = 1.2
n = 5
foldl(|>, Iterators.repeated(exp, n), init = val)
I haven’t benchmarked it, but I’ve found foldl(|>, fs, init = val) to be a pretty useful pattern to compose a list of functions, but of course the other approach with (y, _) -> exp(y) also works if all the functions are equal.
rokke
August 7, 2026, 1:44pm
22
nice, looks like that’s basically the same as the other best ones and is much easier to read:
master:
julia> f(a) = foldl(|>, repeated(exp, 1000); init=a)
f (generic function with 3 methods)
julia> @benchmark f(10.)
BenchmarkTools.Trial: 10000 samples with 999 evaluations per sample.
Range (min … max): 8.245 ns … 184.536 ns ┊ GC (min … max): 0.00% … 0.00%
Time (median): 9.232 ns ┊ GC (median): 0.00%
Time (mean ± σ): 9.830 ns ± 3.589 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▃ ▄▇█▇▃ ▅▃ ▂▁ ▂
█▆▄▄██████▇▆▆▄▄▄▆▄███▇▇▆██▇▆▆▆▆▆▆▆▆▆▆▅▆▇▆▇▇▆▆▆▅▅▅▆▆▆▄▅▄▄▅▄▅ █
8.25 ns Histogram: log(frequency) by time 16.7 ns <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark f($10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 5.883 μs … 112.796 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 7.540 μs ┊ GC (median): 0.00%
Time (mean ± σ): 7.786 μs ± 2.355 μs ┊ GC (mean ± σ): 0.00% ± 0.00%
▂ ▅▅ █▂ ▁▁ ▂▁ ▁
█▅▂██▇▆▇██▇███████▇▇▇▆▆▆▆▄▅▅▅▆▆▅▆██▆▅▅▅▅▃▄▅▅▆▄▃▂▃▂▅▃▃▃▂▂▃▃▅ █
5.88 μs Histogram: log(frequency) by time 17.1 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
Dan
August 8, 2026, 8:03am
23
As DNF suggested, here is a simple loop implementation:
julia> iterated_fnx(f,n,x) = ( while (n -= 1) ≥ 0; x = f(x); end; return x)
iterated_fnx (generic function with 1 method)
julia> iterated_fnx(exp, 3, 1.0)
3.814279104760214e6
It’s compacted a bit, but still as legible as the alternatives IMHO.
It benchmarks with no allocations on Julia 1.11.
rokke
August 8, 2026, 8:12am
24
while loop appears to be a bit slower, maybe since you’ve got an extra n-=1 operation and > check each time:
julia> f1(a) = foldl(|>, repeated(exp, 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> f3(a) = (n=1000; while (n-=1)≥0 a=exp(a) end; a)
f3 (generic function with 1 method)
julia> @benchmark f1($10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 6.554 μs … 25.477 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 6.665 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.824 μs ± 864.537 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▆█▄▁ ▁
█████▇▇▆▆▆▇▇██▇▇▆▆▆▆▆▆▅▅▆▆▆▆▆▆▆▆▅▅▆▅▅▅▅▅▄▅▅▅▄▄▄▄▄▅▄▂▂▃▄▄▃▃▃ █
6.55 μs Histogram: log(frequency) by time 10.6 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark f2($10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 6.564 μs … 25.035 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 6.642 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.868 μs ± 967.479 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
██▂▁ ▁
█████▇▇▆▆▆▆▆▆▅▄▅▅▆▇▇▇▆▇▆▆▆▆▆▅▆▅▅▆▆▅▇▆▆▅▆▆▆▆▄▅▆▆▆▆▆▅▆▅▅▄▅▅▅▄ █
6.56 μs Histogram: log(frequency) by time 11 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark f3($10.)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 7.518 μs … 29.437 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 7.546 μs ┊ GC (median): 0.00%
Time (mean ± σ): 7.719 μs ± 912.501 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
█▄▂▂▁▁ ▁
██████████▇█▇▆▆▇▆▇▆▆▆▆▆▆▆▅▅▆▆▆▆▆▆▅▅▅▅▆▅▆▅▅▆▅▅▅▅▅▅▄▅▄▄▃▃▅▅▄▅ █
7.52 μs Histogram: log(frequency) by time 10.1 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
if you specifically define all three as variables, it becomes equivalent though:
julia> @benchmark f1(exp, $10., 1000)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 5.942 μs … 33.609 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 6.646 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.762 μs ± 646.787 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▅▇█▄▁ ▁▁▁ ▂
▅▁▁▁▁▃▁▁▁███████▇▇█▇██████▆▆▆▇▇▇▆▇▇▆▆▅▆▆▆▅▅▅▅▅▆▆▅▅▅▅▅▅▄▄▅▅▅ █
5.94 μs Histogram: log(frequency) by time 9.67 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark f2(exp, $10., 1000)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 5.962 μs … 24.994 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 6.680 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.927 μs ± 966.049 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▇▇█▂ ▁▁▁ ▁▂▁ ▃ ▂
▃▁▃▁▁▁▁█████▇▇▆█████▇▆▇▇▇███▆▇▆▆▆█▇█▆▆▇▇▆▅▆▆▅▆▆█▅▅▅▄▄▅▄▅▄▅▅ █
5.96 μs Histogram: log(frequency) by time 10.6 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark f3(exp, $10., 1000)
BenchmarkTools.Trial: 10000 samples with 5 evaluations per sample.
Range (min … max): 5.973 μs … 36.853 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 6.675 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.804 μs ± 796.739 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▇██▃▁ ▁▁ ▂
▃▁▁▁▁▁▁▃▁██████▇█▇▇██████▇▆▇▆▇▅▆▆▆▆▆▆▆▇▅▆▆▅▆▅▅▆▅▅▅▅▆▆▄▅▅▅▅█ █
5.97 μs Histogram: log(frequency) by time 9.74 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
You can frequently get a free speed boost by sprinkling @inline there, if it’s a rather heavy function that doesn’t automatically get inlined.
f2(f, a, n) = (for _=1:n a=f(a) end; a)
f3(f, a, n) = (for _=1:n a=@inline(f(a)) end; a)
julia> @benchmark f2(exp, x, 1000) setup=(x=rand())
BenchmarkTools.Trial: 10000 samples with 9 evaluations per sample.
Range (min … max): 2.456 μs … 9.911 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 2.478 μs ┊ GC (median): 0.00%
Time (mean ± σ): 2.605 μs ± 269.830 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
█▇ ▁▇▆ ▁▂ ▅ ▁▁ ▂
██▄▁▅▁▃▁▁▃▄▇███▅██▇▆▅▆▆▆▆▇▅▅█▅██▆▅▁▇█▇▆▆▇▅▇▆▆▅▅▆▆▇▃▅▄▅▃▃▄▁▆ █
2.46 μs Histogram: log(frequency) by time 3.39 μs <
Memory estimate: 0 bytes, allocs estimate: 0.
julia> @benchmark f3(exp, x, 1000) setup=(x=rand())
BenchmarkTools.Trial: 10000 samples with 9 evaluations per sample.
Range (min … max): 2.022 μs … 8.378 μs ┊ GC (min … max): 0.00% … 0.00%
Time (median): 2.033 μs ┊ GC (median): 0.00%
Time (mean ± σ): 2.063 μs ± 170.374 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▅█▄ ▂▁ ▁
███▄▅██▃▃▅▃▁▁▁▁▃▅▇▆▃▆██▁▇▆▆▅▆▆▆▅▅▆▅▁▅▃▅▃▅▃▃▄▁▁▁▁▃▁▁▁▁▄██▆▆▅ █
2.02 μs Histogram: log(frequency) by time 2.62 μs <
Memory estimate: 0 bytes, allocs estimate: 0.