What do you think of `(f1 & f2)(x)`?

There might be a thread or a github issue about that but it’s really hard to search for or and and terms, please redirect me if I missed it

I’d like to use a syntax that looks like that:

f = <(5) & >(1)
g = isnan | ismissing

I can pirate them but obviously I’d rather not:

import Base: &, |
(&)(f1::Function, f2::Function) = x -> f1(x) & f2(x)
(|)(f1::Function, f2::Function) = x -> f1(x) | f2(x)

I looked in here for alternative characters but none looks good to me

(I always mix and so I don’t want to use them)

was there already a discussion about this? Could it be added in Base Julia or is there a reason why it’s not defined?

edit: changed && to & and || to | (doesn’t matter in my case)

1 Like

It’s not a bad idea, but one reason not to do this in Julia base is that it uses the & operator which normally means bitwise AND to mean logical AND. Or, in other words, if you wanted:

(<some_operator>)(f1, f2) = x -> f1(x) & f2(x)

what operator would you use? The & operator seems like the logical and obvious choice, but your proposal would use that to mean something different.

On the other hand, in your own code you could use and and or as function names without needing to pirate anything. Alas, you can’t use them as infix operators, but that may be ok if it makes your code a bit more obvious and free of type piracy.

6 Likes

In the past when I’ve “needed” this (you never really need this though, do you…) I implemented \vee and \wedge like the Base implementation of

"""
    f ∧ g ∧ ...

Create an anonymous function that evaluates to `f(x) && g(x) && ...`
"""
function ∧ end
∧(f) = f
∧(f, g) = (x...) -> f(x...) && g(x...)
∧(f, g, h...) = ∧((f ∧ g), h...)

function ∨ end
∨(f) = f
∨(f, g) = (x...) -> f(x...) || g(x...)
∨(f, g, h...) = ∨((f ∨ g), h...)
julia> map(isascii ∧ isuppercase ∨ isdigit, ('A', '1', 'Σ'))
(true, true, false)

Note that evaluation is “kind-of-short-circuiting”; you can’t replicate && with a function, since it’s control flow, but the evaluation of the function chain will exit early if it hits a false (or true, depending). Also, all arguments to and are evaluated when the anonymous function is created (like with ifelse).
As an exercise a while back I also wrote a macro version of this to overcome the mentioned limitations, but I still haven’t been able to think of a single case where using it would be worthwhile…

macro and(args...)
    ex = Expr(:&&, first(args))
    ex′ = ex
    for i in 2:length(args)
        push!(ex′.args, Expr(:&&, args[i]))
        ex′ = last(ex′.args)
    end
    esc(ex)
end

edit: sorry, I didn’t find the right version of the macro, so the above doesn’t do what I said it does. Oh well…

6 Likes