3

For a fixed n, I would like to create a function with n variables

f(x_1, ..., x_n)

For example if n=3, I would like to create an algorithm such that

f(x_1, x_2, x_3) = x_1 + x_2 + x_3

It would be very nice to have an algorithm for every n:

f(x_1, ..., x_n) = x_1 + ... + x_n

I don't know how to declare the function and how can create the n variables.

Thank you for your help,

Benoit Pasquier
  • 2,868
  • 9
  • 21
Tio Miserias
  • 485
  • 2
  • 8

2 Answers2

5

In Julia you can just do

function f(x...)
     sum(x)
end

And now:

julia> f(1,2,3)
6

Note that within the function f, x is just seen as a Tuple so you can do whatever you want (including asking for type of elements etc).

More generally you can define function f(x...;y...). Let us give it a spin

function f(x...;y...)
    @show x
    @show Dict(y)
end

And now run it:

julia> f(1,2,"hello";a=22, b=777)
x = (1, 2, "hello")
Dict(y) = Dict(:a => 22, :b => 777)
Dict{Symbol, Int64} with 2 entries:
  :a => 22
  :b => 777

Finally, another one (perhaps less elegant) way could be:

g(v::NTuple{3,Int}) = sum(v)

This forces v to be a 3-element Tuple and g be called as g((1,2,3))

Przemyslaw Szufel
  • 40,002
  • 3
  • 32
  • 62
  • And if you want the function f(x_1,x_2,...,x_n) = x_i for some 1 \leq i\leq n. How do you do this? – Tio Miserias Feb 22 '21 at 22:31
  • 1
    If you want a function with let say exactlt 55 `Int` parameters, you could generate it with a `macro` but I would say that using macros in such scenario is an overkill rather than a good Julian style. One less elegant way could be `g(v::NTuple{3,Int}) = sum(v)` which than could be called as `g((1,2,3))`. Hope that helps. – Przemyslaw Szufel Feb 22 '21 at 22:39
  • @Tio For this you can do `f(x...) = x[i]` but it's a bit weird IMHO. – Benoit Pasquier Feb 22 '21 at 23:29
  • 1
    You can use `Base.Cartesian` (see the docs) but I am in firm agreement with posters above that you're better off using tuples for these kinds of things. Instead of passing many arguments just pass a single tuple argument. – tholy Feb 23 '21 at 15:11
1

If your n is small, you can do this manually thanks to multiple dispatch.

julia> f(x) = x + 1   # Method definition for one variable.
f (generic function with 1 method)

julia> f(x, y) = x + y + 1   # Method definition for two variables.
f (generic function with 2 methods)

julia> f(2)
3

julia> f(2, 4)
7

You could use macro programming to generate a set of these methods automatically, but that quickly becomes complicated. You are likely better off structuring your function so that it operates on either a Vector or a Tuple of arbitrary length. The definition of the function will depend on what you want to do. Some examples which expect x to be a Tuple, Vector, or other similar datatype are below.

julia> g(x) = sum(x)   # Add all the elements
g (generic function with 1 method)

julia> h(x) = x[end - 1]   # Return the second to last element
h (generic function with 1 method)

julia> g([10, 11, 12])
33

julia> h([10, 11, 12])
11

If you would rather the function accept an arbitrary number of inputs rather than a single Tuple or Vector as you wrote in the original question, then you should define a method for the functions with the slurping operator ... as below. Note that the bodies of the function definitions and the outputs from the functions are exactly the same as before. Thus, the slurping operator ... is just for syntactical convenience. The functions below still operate on the Tuple x. The function arguments are just slurped into the tuple before doing anything else. Also note that you can define both the above and below methods simultaneously so that the user can choose either input method.

julia> g(x...) = sum(x)   # Add all the variables
g (generic function with 2 methods)

julia> h(x...) = x[end - 1]   # Return the second to last variable
h (generic function with 2 methods)

julia> g(10, 11, 12)
33

julia> h(10, 11, 12)
11

Finally, another trick that is sometimes useful is to call a function recursively. In other words, to have a function call itself (potentially using a different method).

julia> q(x) = 2 * x   # Double the input
q (generic function with 1 method)

julia> q(x...) = q(sum(x)) # Add all the inputs and call the function again on the result
q (generic function with 2 methods)

julia> q(3)
6

julia> q(3, 4, 5)
24
Nathan Boyer
  • 1,412
  • 1
  • 6
  • 20