Recursive function in Julia

Viewed 163

Is there a way in Julia to smoothly define a recursive function?

function f(x_0, y_0)

    x_1 = g1(x_0,y_0)
    y_1 = g2(x_0,y_0)

    x_2 = g1(x_1,y_1)
    y_2 = g2(x_1,y_1)

    x_3 = g1(x_2,y_2)
    y_3 = g2(x_2,y_2)
    
    x_4 = g1(x_3,y_3)
    y_4 = g2(x_3,y_3)
    
    return x_2,y_2
end

In particular, I want to be able to call the function and give parameter that would specify the circle of the recursion. Something like this:

f(x_0, y_0, circle = 2)
>> x_2, y_2
f(x_0, y_0, circle = 3)
>> x_3, y_3
2 Answers

If you define

function apply_n(f, x_0, cycle_len)
    for _ in 1:cycle_len
        x_0 = f(x_0)
    end
    return x0
end

and call apply_n((x,y)->(g1(x,y),g2(x,y)), (x_0,y_0), 3) it will work.

IterTools.jl provides an iterate method that does exatly this.

help?> iterated
  …
  iterated(f, x)

  Iterate over successive applications of f, as in x, f(x), f(f(x)), f(f(f(x))), ...
  …
julia> x_0, y_0 = 5, 10;
       g1 = +;
       g2 = -;

julia> using IterTools: iterated, nth

julia> nth(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 3)
(10, 20)

As the documentation says, the result is (an iterator over) (x, f(x), f(f(x)), …), which means (x_2, y_2) from the question would be f(f(x)) which is the third element - that's why the call to nth above passes 3 as the second argument.

An advantage of this method is that it returns an iterator that you can then treat like any other iterator. So if you instead want the results of all the first 5 stages of the process:

julia> using Base.Iterators: take

julia> take(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 5) |> collect
10-element Vector{Tuple{Int64, Int64}}:
 (5, 10)
 (15, -5)
 (10, 20)
 (30, -10)
 (20, 40)

Or only want the recursion to continue while a condition is true:

julia> using Iterators: takewhile

julia> takewhile(((x, y),) -> x + y < 50, 
                 iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0))) |> collect
4-element Vector{Tuple{Int64, Int64}}:
 (5, 10)
 (15, -5)
 (10, 20)
 (30, -10)
Related