|n> as notation for function piping n times?

Suppose you wanted to repeatedly compose a certain function via piping. For sake of argument, say we want to do

3 |> sqrt |> sqrt |> sqrt |> sqrt

One can do this for an arbitrary number of times n (where n = 4 above) using something relatively convoluted like

3 |> ∘(fill(sqrt,n)...)

I think it would be great to have the following notation in Julia for this:

3 |n> sqrt

Is this even implementable? Thoughts, either for or against?

Why not overload ^ for functions?
At least that would not require changes to the parser.

julia> Base.:(^)(f::Function, n::Integer) = ∘(fill(f,n)...)

julia> sqrt^3
sqrt ∘ sqrt ∘ sqrt

julia> (sqrt^3)(3)
1.147202690439877

julia> cbrt^3
cbrt ∘ cbrt ∘ cbrt

julia> (cbrt^3)(3)
1.041528498231435
6 Likes

See JuliaLang/julia#39042.

4 Likes

Isn’t this syntax ambiguous? One could parse it as (3 | n) > sqrt, where | is bitwise or and > is “greater than”. Currently this fails because isless is not defined for function types, but it isn’t hard to imagine an overload.

2 Likes

Thanks for all the responses. I’m still not clear that repeated piping is precisely the same as using function composition “exponentiation”.

Interestingly, the linked PR also links to issue #41579, where this way using the pipe repeatedly is also recorded:

foldl(|>, Iterators.repeated(foo, n))

and seems to be quite fast among the alternatives.

1 Like

Toying with it a bit…

julia> |>ⁿ(x, (f, n)) = foldl(|>, Iterators.repeated(f, n); init=x)
|>ⁿ (generic function with 1 method)

julia> 3 |>ⁿ (sqrt, 4)
1.0710754830729146
1 Like