# Function `apply`, that calls a function with a tuple of arguments?

Julia makes it very easy to map/broadcast a function over a collection of argument tuples. But I don’t think it makes it so easy to map/broadcast multiple functions over one tuple of arguments.

We can do this:

``````f.((1, 2, 3)) == (f(1), f(2), f(3))
``````

Is there a way to do this?

``````(f, g, h).(1) == (f(1), g(1), h(1))
``````

Obviously this syntax can’t be made to work; it errors with `MethodError: objects of type Tuple{...} are not callable`. But there should be some “apply” function (or is there, and I just can’t find it). Something like this would make sense to me:

``````apply(f::Function, args::Tuple) = f(args...)
@assert apply.((f, g, h), Ref(args)) == (f(args), g(args), h(args))
``````
1 Like

You can use the pipe operator for this:

``````julia> f, g, h = sin, cos, tan
(sin, cos, tan)

julia> 1 .|> (f, g, h)
(0.8414709848078965, 0.5403023058681398, 1.5574077246549023)
``````
7 Likes

Like it, but I then needed horizontal orientation (matrix) for vector input

``````julia> [1 2 3] .|> (sin, cos, tan)
3×3 Matrix{Float64}:
0.841471   0.909297   0.14112
0.540302  -0.416147  -0.989992
1.55741   -2.18504   -0.142547
``````

As alternative one could use a comprehension:

``````julia> apply(funs, x) = [f.(x) for f in funs]
julia> apply((sin, cos, tan), [1,2,3])
3-element Vector{Vector{Float64}}:
[0.8414709848078965, 0.9092974268256817, 0.1411200080598672]
[0.5403023058681398, -0.4161468365471424, -0.9899924966004454]
[1.5574077246549023, -2.185039863261519, -0.1425465430742778]
``````

we must have a previous discussion or even github issue on this I swear

What do you mean? You can do

``````1.7.0> [1,2,3] .|> (sin, cos, tan)
3-element Vector{Float64}:
0.8414709848078965
-0.4161468365471424
-0.1425465430742778
``````

or

``````1.7.0> (1,2,3) .|> (sin, cos, tan)
(0.8414709848078965, -0.4161468365471424, -0.1425465430742778)
``````

these are both columns, what if they want the result of broadcast to be a row?

What do you mean? Isn’t it obvious how to get that?

That’s not the same and so depends on what you want.
In the example, we have 3 functions and 3 input values.
I expect 3x3 output values

Yes, but you seemed to indicate that there was a problem.

But you don’t need horizontal orientation for vector input, you need it for matrix output.

how?

``````julia> [1,2,3] .|> [sin, cos, tan]
3-element Vector{Float64}:
0.8414709848078965
-0.4161468365471424
-0.1425465430742778

julia> [1,2,3] .|> permutedims([sin, cos, tan])
3×3 Matrix{Float64}:
0.841471   0.540302   1.55741
0.909297  -0.416147  -2.18504
0.14112   -0.989992  -0.142547
``````

this doesn’t work, we want a row, not a matrix

A row is a matrix. But anyway:

``````1.7.0> [1 2 3] .|> [sin cos tan]
1×3 Matrix{Float64}:
0.841471  -0.416147  -0.142547

1.7.0> ([1, 2, 3] .|> [sin, cos, tan])'
0.841471  -0.416147  -0.142547
``````

I’m sure there are more ways.

I mean, how is this different from any other examples of broadcasting?

Although `apply` or `funcall` are not as useful in Julia as in some lisps, I sometimes miss them.

An example (completely different from the OP) is that I sometimes wish we could write function barriers like so:

``````arr = Any[1, 2, 3]  # elements of type unknown to the compiler

apply(arr) do x
# This anonymous function will get compiled & specialized for typeof(x)
for _ in 1:1_000_000
do_something_with(x)
end
end
``````

You can easily define your own “apply” function — the syntax `f <| x` is good for this:

``````julia> f <| x = f(x)
<| (generic function with 1 method)

julia> (sin, cos, tan) .<| [1, 2, 3]
3-element Array{Float64,1}:
0.8414709848078965
-0.4161468365471424
-0.1425465430742778

julia> (sin, cos, tan) .<| π
(1.2246467991473532e-16, -1.0, -1.2246467991473532e-16)
``````
1 Like

I’d support this being in `Base`. In fact I find this a more natural (if a tiny bit more verbose) syntax for function calling than parentheses. I think it already meshes well with the rest of Julia. Broadcasting currently looks like `f.([1,2,3])` or `map(f, [1,2,3])` (not quite the same as broadcasting, but sometimes equivalent). In comparison,

1. The relationship between `args |> f` (left associative) and `f <| args` (right associative) is intuitive.
2. If you know about both `+` and `<|`, then it’s easy to extrapolate from `[a,b,c] .+ [1,2,3],` to `[f,g,h] .<| [1,2,3]`, and then to `[f g h] .<| [1,2,3]` (for a matrix of all pairs).
3. There would be a uniform syntax for choosing the direction (LTR or RTL) in which function calls are written.