diff --git a/NEWS.md b/NEWS.md index 5df1b3af51ee9..f05f2c669ab16 100644 --- a/NEWS.md +++ b/NEWS.md @@ -105,6 +105,7 @@ Standard library changes * `RegexMatch` objects can now be probed for whether a named capture group exists within it through `haskey()` ([#36717]). * For consistency `haskey(r::RegexMatch, i::Integer)` has also been added and returns if the capture group for `i` exists ([#37300]). * A new standard library `TOML` has been added for parsing and printing [TOML files](https://toml.io) ([#37034]). +* The composition operator `∘` now returns a `Base.ComposedFunction` instead of an anonymous function ([#37517]). * A new standard library `Downloads` has been added, which replaces the old `Base.download` function with `Downloads.download`, providing cross-platform, multi-protocol, in-process download functionality implemented with [libcurl](https://curl.haxx.se/libcurl/) ([#37340]). * The `Pkg.BinaryPlatforms` module has been moved into `Base` as `Base.BinaryPlatforms` and heavily reworked. Applications that want to be compatible with the old API should continue to import `Pkg.BinaryPlatforms`, diff --git a/base/exports.jl b/base/exports.jl index 121f42db09af9..ac00d7aa8e53a 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -38,6 +38,7 @@ export ComplexF64, ComplexF32, ComplexF16, + ComposedFunction, DenseMatrix, DenseVecOrMat, DenseVector, diff --git a/base/operators.jl b/base/operators.jl index 8f927f03f2e97..fc11b11ed5a32 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -871,26 +871,58 @@ julia> fs = [ julia> ∘(fs...)(3) 3.0 ``` +See also [`ComposedFunction`](@ref). """ function ∘ end -struct ComposedFunction{F,G} <: Function - f::F - g::G - ComposedFunction{F, G}(f, g) where {F, G} = new{F, G}(f, g) - ComposedFunction(f, g) = new{Core.Typeof(f),Core.Typeof(g)}(f, g) +""" + ComposedFunction{Outer,Inner} <: Function + +Represents the composition of two callable objects `outer::Outer` and `inner::Inner`. That is +```julia +ComposedFunction(outer, inner)(args...; kw...) === outer(inner(args...; kw...)) +``` +The preferred way to construct instance of `ComposedFunction` is to use the composition operator [`∘`](@ref): +```jldoctest +julia> sin ∘ cos === ComposedFunction(sin, cos) +true + +julia> typeof(sin∘cos) +ComposedFunction{typeof(sin), typeof(cos)} +``` +The composed pieces are stored in the fields of `ComposedFunction` and can be retrieved as follows: +```jldoctest +julia> composition = sin ∘ cos +sin ∘ cos + +julia> composition.outer === sin +true + +julia> composition.inner === cos +true +``` +!!! compat "Julia 1.6" + ComposedFunction requires at least Julia 1.6. In earlier versions `∘` returns an anonymous function instead. + +See also [`∘`](@ref). +""" +struct ComposedFunction{O,I} <: Function + outer::O + inner::I + ComposedFunction{O, I}(outer, inner) where {O, I} = new{O, I}(outer, inner) + ComposedFunction(outer, inner) = new{Core.Typeof(outer),Core.Typeof(inner)}(outer, inner) end -(c::ComposedFunction)(x...) = c.f(c.g(x...)) +(c::ComposedFunction)(x...) = c.outer(c.inner(x...)) ∘(f) = f ∘(f, g) = ComposedFunction(f, g) ∘(f, g, h...) = ∘(f ∘ g, h...) function show(io::IO, c::ComposedFunction) - show(io, c.f) + show(io, c.outer) print(io, " ∘ ") - show(io, c.g) + show(io, c.inner) end """ diff --git a/doc/src/base/base.md b/doc/src/base/base.md index 180c49f1315bf..b75453f9074e4 100644 --- a/doc/src/base/base.md +++ b/doc/src/base/base.md @@ -237,6 +237,7 @@ Base.invokelatest new Base.:(|>) Base.:(∘) +Base.ComposedFunction ``` ## Syntax