Julia迭代器错误

Julia迭代器错误,julia,Julia,我正在看一个来自的迭代器示例,有一个问题。以下操作将产生最多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();

我正在看一个来自的迭代器示例,有一个问题。以下操作将产生最多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        
文件说:

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
应该失败 因为没有所谓的
状态[2]
。显然,这不是实际情况,因为第一个值是
0
,并且计算过程没有错误。你能指出我的逻辑哪里出错了吗

评论2

对-这有助于:

julia> iterate(FibonacciIterable(BigInt(2), BigInt(3)))
(2, (2, 3))
我假设名为
state
的参数和
iterate
的返回类型(我认为是下一个状态)是相同的类型


正如您所指出的,情况并非如此,因为
状态
参数的类型是
元组{I,I}
,但返回值的类型是
元组{I,元组{I,I}
(实际上
Union{Nothing,Tuple{I,Tuple{I,I}}
,其中“内部”元组是状态。

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

因此,定义
迭代
函数的方法是:

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
iterate(iter::FibonacciIterable, state=(iter.s1-iter.s0, iter.s0)) =
        state[2], (state[2], sum(state))
我们清楚地看到出了问题

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

现在我转换到我的定义:

julia> for F in FibonacciIterable(BigInt(2), BigInt(3))
                  println(F)
                             F > 10 && break
                                    end
2
5
7
12
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(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))

我希望这能有所帮助。

在“格式化和额外空间”问题中添加注释我已经添加了额外的解释。现在清楚了吗?谢谢-在“格式化和额外空间”问题中再次添加注释