Skip to content

Commit 09d617a

Browse files
jw3126StefanKarpinski
authored andcommitted
add one arg function composition (#34251)
1 parent ade4713 commit 09d617a

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ New library functions
2323

2424
New library features
2525
--------------------
26+
* Function composition now works also on one argument `∘(f) = f` (#34251)
2627

2728

2829
Standard library changes

base/operators.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,9 @@ and splatting `∘(fs...)` for composing an iterable collection of functions.
837837
!!! compat "Julia 1.4"
838838
Multiple function composition requires at least Julia 1.4.
839839
840+
!!! compat "Julia 1.5"
841+
Composition of one function ∘(f) requires at least Julia 1.5.
842+
840843
# Examples
841844
```jldoctest
842845
julia> map(uppercase∘first, ["apple", "banana", "carrot"])
@@ -856,6 +859,8 @@ julia> ∘(fs...)(3)
856859
3.0
857860
```
858861
"""
862+
function end
863+
(f) = f
859864
(f, g) = (x...)->f(g(x...))
860865
(f, g, h...) = (f g, h...)
861866

test/operators.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,30 @@ Base.promote_rule(::Type{T19714}, ::Type{Int}) = T19714
111111
@test (x -> x-2, x -> x-3, x -> x+5)(7) == 7
112112
fs = [x -> x[1:2], uppercase, lowercase]
113113
@test (fs...)("ABC") == "AB"
114+
115+
# Like +() and *() we leave ∘() undefined.
116+
# While `∘() = identity` is a reasonable definition for functions, this
117+
# would cause headaches for composition of user defined morphisms.
118+
# See also #34251
119+
@test_throws(MethodError, ())
120+
121+
@test (x -> (x, 1))(0) === (0, 1)
122+
@test (x -> (x, 2), x -> (x, 1))(0) === ((0, 1), 2)
123+
@test (x -> (x, 3), x -> (x, 2), x->(x,1))(0) === (((0, 1), 2), 3)
124+
@test (x -> (x, 4), x -> (x, 3), x->(x,2), x-> (x, 1))(0) === ((((0, 1), 2), 3), 4)
125+
126+
# test that user defined functors only need to overload the two arg version
127+
struct FreeMagma
128+
word
129+
end
130+
Base.:()(a::FreeMagma, b::FreeMagma) = FreeMagma((a.word, b.word))
131+
132+
@test (FreeMagma(1)) === FreeMagma(1)
133+
@test (FreeMagma(1), FreeMagma(2)) === FreeMagma((1,2))
134+
@test (FreeMagma(1), FreeMagma(2), FreeMagma(3)) === FreeMagma(((1,2), 3))
135+
@test (FreeMagma(1), FreeMagma(2), FreeMagma(3), FreeMagma(4)) === FreeMagma((((1,2), 3), 4))
114136
end
137+
115138
@testset "function negation" begin
116139
str = randstring(20)
117140
@test filter(!isuppercase, str) == replace(str, r"[A-Z]" => "")

0 commit comments

Comments
 (0)