Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose ComposedFunction as a public API #37517

Merged
merged 15 commits into from
Sep 24, 2020
Merged
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,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]).

#### LinearAlgebra
* New method `LinearAlgebra.issuccess(::CholeskyPivoted)` for checking whether pivoted Cholesky factorization was successful ([#36002]).
Expand Down
44 changes: 36 additions & 8 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -871,26 +871,54 @@ julia> fs = [
julia> ∘(fs...)(3)
3.0
```
See also [`Base.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)
"""
Base.ComposedFunction{Outer,Inner} <: Function

Represents the composition of two callable objects `f::Outer` and `g::Inner`.
```jldoctest
julia> sin ∘ cos === Base.ComposedFunction(sin, cos)
true

julia> typeof(sin∘cos)
Base.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 version `∘` returns an anonymous function instead.

See also [`∘`](@ref).
"""
struct ComposedFunction{O,I} <: Function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, This is coming very late.

Just wanted to find out if it is necessary to restrict O and I to be subtypes of Base.Callable as in

struct ComposedFunction{O<:Base.Callable, I<:Base.Callable} <: Function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no reason to restrict to Callable here. There are lots of callable objects that aren't a subtype of Callable and this would break those cases.

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

"""
Expand Down
1 change: 1 addition & 0 deletions doc/src/base/base.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ Base.invokelatest
new
Base.:(|>)
Base.:(∘)
Base.ComposedFunction
```

## Syntax
Expand Down