diff --git a/README.md b/README.md index ab9ff38a4..6d5cebf4a 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,8 @@ Currently, the `@compat` macro supports the following syntaxes: `cov(::AbstractVector; corrected=)` and `cov(::AbstractVector, ::AbstractVector; corrected=)` are only available on 0.6. ([#21709]) -* `equalto` constructs an `EqualTo` object that can be used as a predicate ([#23812]). +* `isequal`, `==` and `in` have one argument "curried" forms. For example `isequal(x)` + returns a function that compares its arguments to `x` using `isequal` ([#26436]). * `*(::Union{Char,AbstractString},::Union{Char,AbstractString})` concatenation. ([#22512]) @@ -350,18 +351,18 @@ Currently, the `@compat` macro supports the following syntaxes: * `find` is now `findall` ([#25545]). * `search` is now `findfirst`/`findnext` and `rsearch` is now `findlast`/`findprev`, - sometimes combined with `equalto` or `occursin` ([#24673]). + sometimes combined with `isequal` or `in` ([#24673], [#26436]). * `Compat.findfirst`, `Compat.findnext`, `Compat.findlast` and `Compat.findprev`, return `nothing` when no match is found (rather than `0` or `0:-1`) as on Julia 0.7 ([#24673], [#26149]). -* `findin(a, b)` is now `findall(occursin(b), a)` ([#24673]). +* `findin(a, b)` is now `findall(in(b), a)` ([#24673]). * `indmin` and `indmax` are now `argmin` and `argmax`, respectively ([#25654]). * `Compat.indexin` accepts any iterable as first argument, returns `nothing` (rather than `0`) - for entries with no match and gives the index of the first (rather than the last) match + for entries with no match and gives the index of the first (rather than the last) match ([#25662], [#25998]). * `isabstract` and `isleaftype` are now `isabstracttype` and `isconcretetype`, respectively @@ -532,7 +533,6 @@ includes this fix. Find the minimum version from there. [#23642]: https://github.com/JuliaLang/julia/issues/23642 [#23666]: https://github.com/JuliaLang/julia/issues/23666 [#23757]: https://github.com/JuliaLang/julia/issues/23757 -[#23812]: https://github.com/JuliaLang/julia/issues/23812 [#23931]: https://github.com/JuliaLang/julia/issues/23931 [#24047]: https://github.com/JuliaLang/julia/issues/24047 [#24182]: https://github.com/JuliaLang/julia/issues/24182 @@ -599,4 +599,5 @@ includes this fix. Find the minimum version from there. [#26149]: https://github.com/JuliaLang/julia/issues/26149 [#26156]: https://github.com/JuliaLang/julia/issues/26156 [#26316]: https://github.com/JuliaLang/julia/issues/26316 -[#26442]: https://github.com/JuliaLang/julia/issues/26442 \ No newline at end of file +[#26436]: https://github.com/JuliaLang/julia/issues/26436 +[#26442]: https://github.com/JuliaLang/julia/issues/26442 diff --git a/src/Compat.jl b/src/Compat.jl index 35bef8b61..36757a21e 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -868,28 +868,27 @@ else import Serialization end -# 0.7.0-DEV.1993 -@static if !isdefined(Base, :EqualTo) - if VERSION >= v"0.6.0" - include_string(@__MODULE__, """ - struct EqualTo{T} <: Function - x::T - - EqualTo(x::T) where {T} = new{T}(x) - end - """) - else - include_string(@__MODULE__, """ - immutable EqualTo{T} <: Function - x::T - end - """) +@static if VERSION < v"0.7.0-DEV.4592" + struct Fix2{F,T} <: Function + f::F + x::T + Fix2(f::F, x::T) where {F,T} = new{F,T}(f, x) + Fix2(f::Type{F}, x::T) where {F,T} = new{F,T}(f, x) end - (f::EqualTo)(y) = isequal(f.x, y) - const equalto = EqualTo + (f::Fix2)(y) = f.f(y, f.x) + + Base.isequal(x) = Fix2(isequal, x) + Base.:(==)(x) = Fix2(==, x) + Base.in(x) = Fix2(in, x) +end +# # keep these definitions to be non breaking for 0.6 usage +@static if VERSION < v"0.7.0-DEV.1993" + const EqualTo = Fix2{typeof(isequal)} export equalto + equalto(x) = isequal(x) end + # 0.7.0-DEV.912 if VERSION < v"0.7.0-DEV.912" import Base.* @@ -1486,14 +1485,10 @@ end findprev(xs...) = Base.findprev(xs...) findlast(xs...) = Base.findlast(xs...) else - struct OccursIn{T} <: Function - x::T - - OccursIn(x::T) where {T} = new{T}(x) - end - (f::OccursIn)(y) = y in f.x - const occursin = OccursIn + # keep these definitions to be non breaking for 0.6 usage + const OccursIn = Fix2{typeof(in)} export occursin + occursin(x) = in(x) zero2nothing(x::Integer) = x == 0 ? nothing : x zero2nothing(x::AbstractUnitRange{<:Integer}) = x == 0:-1 ? nothing : x @@ -1506,41 +1501,41 @@ else Base.findnext(r::Regex, s::AbstractString, idx::Integer) = search(s, r, idx) Base.findfirst(r::Regex, s::AbstractString) = search(s, r) - Base.findnext(c::EqualTo{Char}, s::AbstractString, i::Integer) = search(s, c.x, i) - Base.findfirst(c::EqualTo{Char}, s::AbstractString) = search(s, c.x) - Base.findnext(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) = + Base.findnext(c::Fix2{typeof(isequal),Char}, s::AbstractString, i::Integer) = search(s, c.x, i) + Base.findfirst(c::Fix2{typeof(isequal),Char}, s::AbstractString) = search(s, c.x) + Base.findnext(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) = search(a, b.x, i) - Base.findfirst(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) = + Base.findfirst(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) = search(a, b.x) - Base.findnext(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, + Base.findnext(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, s::AbstractString, i::Integer) = search(s, c.x, i) - Base.findfirst(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, + Base.findfirst(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, s::AbstractString) = search(s, c.x) Base.findnext(t::AbstractString, s::AbstractString, i::Integer) = search(s, t, i) Base.findfirst(t::AbstractString, s::AbstractString) = search(s, t) - Base.findfirst(delim::EqualTo{UInt8}, buf::Base.IOBuffer) = search(buf, delim.x) + Base.findfirst(delim::Fix2{typeof(isequal),UInt8}, buf::Base.IOBuffer) = search(buf, delim.x) - Base.findprev(c::EqualTo{Char}, s::AbstractString, i::Integer) = rsearch(s, c.x, i) - Base.findlast(c::EqualTo{Char}, s::AbstractString) = rsearch(s, c.x) - Base.findprev(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) = + Base.findprev(c::Fix2{typeof(isequal),Char}, s::AbstractString, i::Integer) = rsearch(s, c.x, i) + Base.findlast(c::Fix2{typeof(isequal),Char}, s::AbstractString) = rsearch(s, c.x) + Base.findprev(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) = rsearch(a, b.x, i) - Base.findlast(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) = + Base.findlast(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) = rsearch(a, b.x) - Base.findprev(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, + Base.findprev(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, s::AbstractString, i::Integer) = rsearch(s, c.x, i) - Base.findlast(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, + Base.findlast(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}, s::AbstractString) = rsearch(s, c.x) Base.findprev(t::AbstractString, s::AbstractString, i::Integer) = rsearch(s, t, i) Base.findlast(t::AbstractString, s::AbstractString) = rsearch(s, t) - findall(b::OccursIn, a) = findin(a, b.x) + findall(b::Fix2{typeof(in)}, a) = findin(a, b.x) # To fix ambiguity - findall(b::OccursIn, a::Number) = a in b.x ? [1] : Vector{Int}() + findall(b::Fix2{typeof(in)}, a::Number) = a in b.x ? [1] : Vector{Int}() end @static if VERSION < v"0.7.0-DEV.4047" #26089 diff --git a/test/runtests.jl b/test/runtests.jl index d04a1f55b..87a2027a2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -947,13 +947,21 @@ module Test24648 end let a = [0,1,2,3,0,1,2,3] - @test findfirst(equalto(3), [1,2,4,1,2,3,4]) == 6 - @test findfirst(!equalto(1), [1,2,4,1,2,3,4]) == 2 - @test findnext(equalto(1), a, 4) == 6 - # @test findnext(equalto(5), a, 4) == 0 - @test findlast(equalto(3), [1,2,4,1,2,3,4]) == 6 - @test findprev(equalto(1), a, 4) == 2 - @test findprev(equalto(1), a, 8) == 6 + # curried isequal + @test findfirst(isequal(3), [1,2,4,1,2,3,4]) == 6 + @test findfirst(!isequal(1), [1,2,4,1,2,3,4]) == 2 + @test findnext(isequal(1), a, 4) == 6 + # @test findnext(isequal(5), a, 4) == 0 + @test findlast(isequal(3), [1,2,4,1,2,3,4]) == 6 + @test findprev(isequal(1), a, 4) == 2 + @test findprev(isequal(1), a, 8) == 6 + # curried == + @test findfirst(==(3), [1,2,4,1,2,3,4]) == 6 + @test findfirst(!==(1), [1,2,4,1,2,3,4]) == 2 + @test findnext(==(1), a, 4) == 6 + @test findlast(==(3), [1,2,4,1,2,3,4]) == 6 + @test findprev(==(1), a, 4) == 2 + @test findprev(==(1), a, 8) == 6 end # 0.7 @@ -1358,24 +1366,24 @@ end for (f1, f2, i) in ((Compat.findfirst, Compat.findnext, 1), (Compat.findlast, Compat.findprev, 2)) # Generic methods - @test f1(equalto(0), [1, 0]) == f2(equalto(0), [1, 0], i) == 2 - @test f1(equalto(9), [1, 0]) == f2(equalto(9), [1, 0], i) == nothing - @test f1(occursin([0, 2]), [1, 0]) == f2(occursin([0, 2]), [1, 0], i) == 2 - @test f1(occursin([0, 2]), [1, 9]) == f2(occursin([0, 2]), [1, 9], i) == nothing + @test f1(isequal(0), [1, 0]) == f2(isequal(0), [1, 0], i) == 2 + @test f1(isequal(9), [1, 0]) == f2(isequal(9), [1, 0], i) == nothing + @test f1(in([0, 2]), [1, 0]) == f2(in([0, 2]), [1, 0], i) == 2 + @test f1(in([0, 2]), [1, 9]) == f2(in([0, 2]), [1, 9], i) == nothing @test f1([true, false]) == f2([true, false], i) == 1 @test f1([false, false]) == f2([false, false], i) == nothing # Specific methods - @test f2(equalto('a'), "ba", i) == f1(equalto('a'), "ba") == 2 + @test f2(isequal('a'), "ba", i) == f1(isequal('a'), "ba") == 2 for S in (Int8, UInt8), T in (Int8, UInt8) # Bug in Julia 0.6 f1 === Compat.findlast && VERSION < v"0.7.0-DEV.3272" && continue - @test f2(equalto(S(1)), T[0, 1], i) == f1(equalto(S(1)), T[0, 1]) == 2 - @test f2(equalto(S(9)), T[0, 1], i) == f1(equalto(S(9)), T[0, 1]) == nothing + @test f2(isequal(S(1)), T[0, 1], i) == f1(isequal(S(1)), T[0, 1]) == 2 + @test f2(isequal(S(9)), T[0, 1], i) == f1(isequal(S(9)), T[0, 1]) == nothing end for chars in (['a', 'z'], Set(['a', 'z']), ('a', 'z')) - @test f2(occursin(chars), "ba", i) == f1(occursin(chars), "ba") == 2 - @test f2(occursin(chars), "bx", i) == f1(occursin(chars), "bx") == nothing + @test f2(in(chars), "ba", i) == f1(in(chars), "ba") == 2 + @test f2(in(chars), "bx", i) == f1(in(chars), "bx") == nothing end end @test findnext("a", "ba", 1) == findfirst("a", "ba") == 2:2 @@ -1392,11 +1400,11 @@ end @test Compat.findnext(r"a", "ba", 1) == Compat.findfirst(r"a", "ba") == 2:2 @test Compat.findnext(r"z", "ba", 1) == Compat.findfirst(r"z", "ba") == nothing -@test Compat.findfirst(equalto(UInt8(0)), IOBuffer(UInt8[1, 0])) == 2 -@test Compat.findfirst(equalto(UInt8(9)), IOBuffer(UInt8[1, 0])) == nothing +@test Compat.findfirst(isequal(UInt8(0)), IOBuffer(UInt8[1, 0])) == 2 +@test Compat.findfirst(isequal(UInt8(9)), IOBuffer(UInt8[1, 0])) == nothing @test findall([true, false, true]) == [1, 3] -@test findall(occursin([1, 2]), [1]) == [1] +@test findall(in([1, 2]), [1]) == [1] # 0.7.0-DEV.3666 module TestUUIDs