Julia迭代器错误
我正在看一个来自的迭代器示例,有一个问题。以下操作将产生最多13个斐波那契数: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();
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}}
,其中“内部”元组是状态。您必须只传递状态,所以aTuple{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))
我希望这能有所帮助。在“格式化和额外空间”问题中添加注释我已经添加了额外的解释。现在清楚了吗?谢谢-在“格式化和额外空间”问题中再次添加注释