[疑问]在尾递归中Iterators.rest行为怪异

在写欧拉计划用到尾递归的时候,我发现Iterators.rest这个函数行为很怪异,
这是用到rest的尾递归函数

function iter1(nums,res)
    num = first(nums)
    if num > 10
        res
    else
        iter1(Iterators.rest(nums,1),res + num)
    end
end

定义主函数

function main()
    nums = Iterators.countfrom(1,1)
    print(iter1(nums,0))
end

发现栈溢出错误

-*- mode: compilation; default-directory: "~/workspace/test/" -*-
Compilation started at Mon Apr 27 18:14:17

julia rest.jl 
ERROR: LoadError: StackOverflowError:
Stacktrace:
 [1] Rest at ./iterators.jl:446 [inlined] (repeats 2 times)
 [2] rest at ./iterators.jl:465 [inlined]
 [3] iter1(::Base.Iterators.Rest{Base.Iterators.Count{Int64},Int64}, ::Int64) at /home/steiner/disk/disk1/workspace/test/rest.jl:6 (repeats 80000 times)
in expression starting at /home/steiner/disk/disk1/workspace/test/rest.jl:14

Compilation exited abnormally with code 1 at Mon Apr 27 18:14:19

那我换个相似的函数,Iterators.drop

function iter2(nums,res)
    num = first(nums)
    if num > 10
        res
    else
        iter2(Iterators.drop(nums,1),res + num)
    end
end

调用主函数

function main()
    nums = Iterators.countfrom(1,1)
    print(iter2(nums,0))
end

完全没问题,还实现了惰性

-*- mode: compilation; default-directory: "~/workspace/test/" -*-
Compilation started at Mon Apr 27 18:15:55

julia rest.jl 
55
Compilation finished at Mon Apr 27 18:15:55

现在我总感觉这个rest是个鸡肋函数,没什么用啊

从源代码中可以看到,重复构造rest的时候状态会被重置drop的状态则会保留

julia> it = rest(1:10, 1)
Base.Iterators.Rest{UnitRange{Int64},Int64}(1:10, 1)

julia> rest(it, 1) === it
true

julia> first(it)
2

julia> first(rest(it, 1))
2

所以递归的时候还需要传递state参数进来

julia> function iter1(nums, res, state)
           num = first(nums)
           if num > 10
               res
           else
               iter1(Iterators.rest(nums,state),res + num, state+1)
           end
       end
iter1 (generic function with 1 method)

julia> function main()
           nums = Iterators.countfrom(1,1)
           print(iter1(nums,0, 1))
       end
main (generic function with 1 method)

julia> main()
56

京ICP备17009874号-2