Skip to content

Commit

Permalink
predicate function negation with ComposedFunction (#44752)
Browse files Browse the repository at this point in the history
Co-authored-by: Mosè Giordano <[email protected]>

Co-authored-by: Mosè Giordano <[email protected]>
  • Loading branch information
markmbaum and giordano committed Apr 12, 2022
1 parent c0c60e8 commit d4e26c8
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Library changes
as `keys(::Dict)`, `values(::Dict)`, and `Set` is fixed. These methods of `iterate` can
now be called on a dictionary or set shared by arbitrary tasks provided that there are no
tasks mutating the dictionary or set ([#44534]).
* Predicate function negation `!f` now returns a composed function `(!) ∘ f` instead of an anonymous function ([#44752]).


Standard library changes
Expand Down
39 changes: 34 additions & 5 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1022,16 +1022,41 @@ end
(f, g, h...) = (f g, h...)

function show(io::IO, c::ComposedFunction)
show(io, c.outer)
c.outer isa ComposedFunction ? show(io, c.outer) : _showcomposed(io, c.outer)
print(io, "")
show(io, c.inner)
_showcomposed(io, c.inner)
end

#shows !f instead of (!) ∘ f when ! is the outermost function
function show(io::IO, c::ComposedFunction{typeof(!)})
print(io, '!')
_showcomposed(io, c.inner)
end

_showcomposed(io::IO, x) = show(io, x)
#display operators like + and - inside parens
_showcomposed(io::IO, f::Function) = isoperator(Symbol(f)) ? (print(io, '('); show(io, f); print(io, ')')) : show(io, f)
#nesting for chained composition
_showcomposed(io::IO, f::ComposedFunction) = (print(io, '('); show(io, f); print(io, ')'))
#no nesting when ! is the outer function in a composition chain
_showcomposed(io::IO, f::ComposedFunction{typeof(!)}) = show(io, f)

function show_function(io::IO, c::ComposedFunction, compact::Bool)
if compact
show(io, c)
else
print(io, "ComposedFunction(")
show_function(io, c.outer, false)
print(io, ", ")
show_function(io, c.inner, false)
print(io, ')')
end
end

"""
!f::Function
Predicate function negation: when the argument of `!` is a function, it returns a
function which computes the boolean negation of `f`.
Predicate function negation: when the argument of `!` is a function, it returns a composed function which computes the boolean negation of `f`.
See also [`∘`](@ref).
Expand All @@ -1046,8 +1071,12 @@ julia> filter(isletter, str)
julia> filter(!isletter, str)
"∀ > 0, ∃ > 0: |-| < ⇒ |()-()| < "
```
!!! compat "Julia 1.9"
Starting with Julia 1.9, `!f` returns a [`ComposedFunction`](@ref) instead of an anonymous function.
"""
!(f::Function) = (x...)->!f(x...)
!(f::Function) = (!) f
!(f::ComposedFunction{typeof(!)}) = f.inner #allows !!f === f

"""
Fix1(f, x)
Expand Down
3 changes: 3 additions & 0 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,12 @@ function show_function(io::IO, f::Function, compact::Bool)
end
end

show_function(io::IO, x, ::Bool) = show(io, x)

show(io::IO, f::Function) = show_function(io, f, get(io, :compact, false)::Bool)
print(io::IO, f::Function) = show_function(io, f, true)


function show(io::IO, f::Core.IntrinsicFunction)
if !(get(io, :compact, false)::Bool)
print(io, "Core.Intrinsics.")
Expand Down
6 changes: 6 additions & 0 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ end
str = randstring(20)
@test filter(!isuppercase, str) == replace(str, r"[A-Z]" => "")
@test filter(!islowercase, str) == replace(str, r"[a-z]" => "")
@test !!isnan === isnan
@test repr(!isnan) == "!isnan"
@test repr((-) sin) == "(-) ∘ sin"
@test repr(cos (sin tan)) == "cos ∘ (sin ∘ tan)"
@test repr(!(cos !sin)) == "!(cos ∘ !sin)"
@test repr(cos sin tan) == "cos ∘ sin ∘ tan" == repr((cos sin) tan)
end

# issue #19891
Expand Down

0 comments on commit d4e26c8

Please sign in to comment.