【问题标题】:A Julia iterator errorJulia 迭代器错误
【发布时间】:2019-01-22 14:58:40
【问题描述】:

我正在查看来自http://lostella.github.io/blog/2018/07/25/iterative-methods-done-right 的迭代器示例并有一个问题。以下工作并产生高达 13 的斐波那契数:

iterate(f::FibonacciIterable) = f.s0, (f.s0, f.s1)
iterate(f::FibonacciIterable, state) = state[2], (state[2], state[1] + state[2])

for f in FibonacciIterable(0, 1)
    print("$f ")
    if f > 10 println(); break end
end

我正在尝试将两个 iterate 函数替换为一个,并配置了默认值:

iterate(f::FibonacciIterable, state = (f.s0, (f.s0, f.s1)) ) = (state[2], state[1] + state[2])

运行此代码会产生:

ERROR: LoadError: MethodError: no method matching +(::Int64, ::Tuple{Int64,Int64})
Closest candidates are:
  +(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:502
  +(::T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8}, !Matched::T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8}) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:53
  +(::Union{Int16, Int32, Int64, Int8}, !Matched::BigInt) at gmp.jl:456        

注意:使用 Julia 1.0

在此评论 Bogumił Kamiński 的关于格式化和额外空间的回答

谢谢 Bogumił - 但我仍然很难建立一个关于其工​​作原理的心智模型。首先还有以下 产生预期的输出:

iterate(iter::FibonacciIterable, state=(iter.s1, iter.s0)) = state[2], (state[2], sum(state))

文档说:

iterate(iter [, state]) -> Union{Nothing, Tuple{Any, Any}}

Advance the iterator to obtain the next element. If no elements remain, nothing should be returned. 
Otherwise, a 2-tuple of the next element and the new iteration state should be returned.

按照我的阅读方式,第一次调用这个版本的iterate会返回iter.s1并设置下一个状态 成为iter.s0。所以第一次调用的输出应该是1,而下一次调用iterate 应该会失败 因为没有 state[2] 这样的东西。显然这不是正在发生的事情,因为第一个值是 0 并且计算继续进行而没有错误。你能指出我的逻辑哪里出错了吗?

评论 2

正确 - 这有帮助:

julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)))
(2, (2, 3))

我假设名为state 的参数和iterate 的返回类型(我认为是下一个状态)属于同一类型。

正如您指出的那样,state 参数的类型不是Tuple{I,I},但返回值的类型是Tuple{I, Tuple{I,I}}(实际上是Union{Nothing, Tuple{I, Tuple{I,I}}},但没关系)其中“内部”元组是状态。

【问题讨论】:

    标签: julia


    【解决方案1】:

    你必须只传递状态,所以 Tuple{I, I} where {I} 而不是 Tuple{I, Tuple{I, I}} where {I}。在这种情况下,您还必须在斐波那契数列中返回一步才能获得正确的第一步(即存储在 iter.s0 中的值)。

    因此,您可以定义 iterate 函数的方式是:

    iterate(iter::FibonacciIterable, state=(iter.s1-iter.s0, iter.s0)) =
        state[2], (state[2], sum(state))
    

    现在一切都按预期工作了:

    julia> for F in FibonacciIterable(BigInt(0), BigInt(1))
               println(F)
               F > 10 && break
           end
    0
    1
    1
    2
    3
    5
    8
    13
    

    编辑:提到您的其他问题。

    如果您将定义更改为:

    iterate(iter::FibonacciIterable, state=(iter.s1, iter.s0)) = state[2],
            (state[2], sum(state))
    

    迭代将不正确。使用您的定义时请考虑以下示例:

    julia> for F in FibonacciIterable(BigInt(2), BigInt(3))
                      println(F)
                                 F > 10 && break
                                        end
    2
    5
    7
    12
    

    我们清楚地看到出了问题。

    为了理解这个案例,您必须建立一个心智模型,在我们的练习中什么是迭代器状态。它是以下形式的元组(fibonacci(n), fibonacci(n+1),即第一个是元素n,第二个是元素n+1

    现在我切换到我的定义:

    iterate(iter::FibonacciIterable, state=(iter.s1-iter.s0, iter.s0)) =
            state[2], (state[2], sum(state))
    

    让我们检查一下运行这些行时会发生什么:

    julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)))
    (2, (2, 3))
    
    julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)), (2, 3))
    (3, (3, 5))
    
    julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)), (3, 5))
    (5, (5, 8))
    

    在第一行iterate 告诉您第一个元素是2,在下一次迭代中使用的状态是(2,3)。所以在第二行中,我们使用这个状态来获得下一次迭代:值3 和下一个状态(3,5)。我们继续使用这个新状态来获取下一个值5 和下一个状态(5,8)

    我想在这个例子中混淆是状态是一个元组,但iterate 返回的是一个元组。可能更具有指导意义的方法是定义一个新的迭代状态类型:

    struct FiboState{I}
        a::I
        b::I
    end
    

    以及iterate的以下定义:

    iterate(iter::FibonacciIterable, state=FiboState(iter.s1-iter.s0, iter.s0)) =
            state.b, FiboState(state.b, state.a+state.b)
    

    现在我们清楚地看到发生了什么:

    julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)))
    (2, FiboState{BigInt}(2, 3))
    
    julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)), FiboState{BigInt}(2, 3))
    (3, FiboState{BigInt}(3, 5))
    
    julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)), FiboState{BigInt}(3, 5))
    (5, FiboState{BigInt}(5, 8))
    

    我希望这会有所帮助。

    【讨论】:

    • 在问题中评论格式化和额外空间
    • 我添加了一个额外的解释。现在清楚了吗?
    • 谢谢 - 再次评论格式化和额外空间的问题
    猜你喜欢
    • 1970-01-01
    • 2016-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多