From c8313c62b30ee3b04e2e2248bb0fab2c23cdde85 Mon Sep 17 00:00:00 2001 From: Jeff Fessler Date: Tue, 15 Oct 2019 23:01:18 -0500 Subject: [PATCH] Enable multiple function composition in prefix form (#33568) Document the prefix form and extend the prefix form to support composition of 3 or more functions. Co-Authored-By: Stefan Karpinski --- NEWS.md | 3 +++ base/operators.jl | 19 ++++++++++++++++++- test/operators.jl | 5 ++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index a47056e19127a..f7afd2de59434 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,9 @@ New language features * `import` now allows quoted symbols, e.g. `import Base.:+` ([#33158]). +* Function composition now supports multiple functions: `∘(f, g, h) = f ∘ g ∘ h` +and splatting `∘(fs...)` for composing an iterable collection of functions ([#33568]). + Language changes ---------------- diff --git a/base/operators.jl b/base/operators.jl index 51105d21c2816..232f6407ed6f5 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -827,6 +827,13 @@ julia> [1:5;] |> x->x.^2 |> sum |> inv Compose functions: i.e. `(f ∘ g)(args...)` means `f(g(args...))`. The `∘` symbol can be entered in the Julia REPL (and most editors, appropriately configured) by typing `\\circ`. +Function composition also works in prefix form: `∘(f, g)` is the same as `f ∘ g`. +The prefix form supports composition of multiple functions: `∘(f, g, h) = f ∘ g ∘ h` +and splatting `∘(fs...)` for composing an iterable collection of functions. + +!!!compat "Julia 1.4" + Multiple function composition requires at least Julia 1.4. + # Examples ```jldoctest julia> map(uppercase∘first, ["apple", "banana", "carrot"]) @@ -834,10 +841,20 @@ julia> map(uppercase∘first, ["apple", "banana", "carrot"]) 'A' 'B' 'C' + +julia> fs = [ + x -> 2x + x -> x/2 + x -> x-1 + x -> x+1 + ]; + +julia> ∘(fs...)(3) +3.0 ``` """ ∘(f, g) = (x...)->f(g(x...)) - +∘(f, g, h...) = ∘(f ∘ g, h...) """ !f::Function diff --git a/test/operators.jl b/test/operators.jl index 467d3aa755e2c..58102d7d65a32 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -105,9 +105,12 @@ Base.convert(::Type{T19714}, ::Int) = T19714() Base.promote_rule(::Type{T19714}, ::Type{Int}) = T19714 @test T19714()/1 === 1/T19714() === T19714() -# pr #17155 +# pr #17155 and #33568 @testset "function composition" begin @test (uppercase∘(x->string(x,base=16)))(239487) == "3A77F" + @test ∘(x -> x-2, x -> x-3, x -> x+5)(7) == 7 + fs = [x -> x[1:2], uppercase, lowercase] + @test ∘(fs...)("ABC") == "AB" end @testset "function negation" begin str = randstring(20)