Julia 中的递归函数

Recursive function in Julia

Julia 有没有办法顺利定义递归函数?

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

特别是,我希望能够调用函数并提供指定递归循环的参数。像这样:

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

如果你定义

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

并调用 apply_n((x,y)->(g1(x,y),g2(x,y)), (x_0,y_0), 3) 它会起作用。

IterTools.jl 提供了一个 iterate 方法可以做到这一点。

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)

正如文档所说,结果是(迭代器)(x, f(x), f(f(x)), …),这意味着问题中的 (x_2, y_2) 将是 f(f(x)),这是第三个元素 - 这就是为什么上面对 nth 的调用将 3 作为第二个参数传递。

此方法的一个优点是它 returns 一个迭代器,您可以像对待任何其他迭代器一样对待它。因此,如果您想要该过程所有前 5 个阶段的结果:

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)

或者只希望递归在条件为真时继续:

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)