从python3到Julia,人们都希望能够将快速迭代器作为一个函数编写,并具有生成/输出语法或类似的功能。
julia的宏似乎表明,可以构建一个宏,将这样的“生成器”函数转换为julia迭代器。[您甚至可以轻松地使用函数样式编写内联迭代器,这是Iterators.jl包还试图为其特定的迭代器https://github.com/JuliaCollections/Iterators.jl#the-itr-macro-for-automatic-inlining-in-for-loops提供的特性]
举一个例子说明我的想法:
@asiterator function myiterator(as::Array)
b = 1
for (a1, a2) in zip(as, as[2:end])
try
@produce a1[1] + a2[2] + b
catch exc
end
end
end
for i in myiterator([(1,2), (3,1), 3, 4, (1,1)])
@show i
end理想情况下,myiterator应该创建一个尽可能低开销的快速迭代器。当然,这只是一个具体的例子。理想情况下,我希望有一个可以工作于所有或几乎所有生成器功能的东西。
目前推荐的将生成器函数转换为迭代器的方法是通过Julia的任务完成的,至少据我所知。然而,它们似乎也比纯迭代器慢得多。例如,如果您可以使用简单的迭代器(如imap、chain等)来表示您的函数(由Iterators.jl包提供),这似乎是非常可取的。
从理论上讲,朱莉娅是否有可能将生成函数转换为灵活的快速迭代器?
额外的问题:如果这是可能的话,是否会有一个通用的宏来内联这样的迭代器?
发布于 2017-05-04 23:11:24
此表单的一些迭代器可以如下所示:
myiterator(as) = (a1[1] + a2[2] + 1 for (a1, a2) in zip(as, as[2:end]))此代码可以(潜在地)内联。
为了全面推广这一点,理论上可以编写一个宏,将其参数转换为延续传递样式(CPS),从而可以暂停和重新启动执行,从而提供类似迭代器的东西。分隔的延续特别适合于此(continuation)。结果是一个庞大的匿名函数巢,它可能比任务切换更快,但不一定,因为在一天结束时,它需要堆-分配类似数量的状态。
我碰巧在这里有一个这样的转换的例子(虽然是女性,而不是朱莉娅):https://github.com/JeffBezanson/femtolisp/blob/master/examples/cps.lsp,它的结尾是一个define-generator宏,执行您所描述的。但我不确定是否值得为朱莉娅这么做。
发布于 2017-04-25 16:34:03
朱莉娅中的Python风格的生成器- which最接近于从- involve任务中产生相当数量的固有开销。您必须切换任务,这是不平凡的,不能直接被编译器淘汰。这就是为什么Julia的迭代器基于转换一个典型不变的、简单的状态值和另一个的函数。长话短说:不,我不相信这种转变是可以自动完成的。
发布于 2017-05-18 16:53:54
在考虑了如何在不影响性能的情况下将python生成器转换为Julia之后,我实现并测试了一个高级函数库,该库以延续风格实现类似Python/任务的生成器。https://github.com/schlichtanders/Continuables.jl
本质上,我们的想法是将Python的yield /Julia的produce看作是我们从外部接受的一个额外的参数。我叫它cont是为了继续。例如,查看这个范围的重新实现。
crange(n::Integer) = cont -> begin
for i in 1:n
cont(i)
end
end您可以简单地用以下代码对所有整数进行求和
function sum_continuable(continuable)
a = Ref(0)
continuable() do i
a.x += i
end
a.x
end
# which simplifies with the macro Continuables.@Ref to
@Ref function sum_continuable(continuable)
a = Ref(0)
continuable() do i
a += i
end
a
end
sum_continuable(crange(4)) # 10正如您所希望的那样,您可以像在python中使用生成器或在julia中使用任务一样使用可扩展性。使用do符号而不是for循环是您必须习惯的一件事。
这个想法真的让你走得很远。使用这种思想不能完全实现的唯一标准方法是zip。所有其他标准的高级工具都像你希望的那样工作。
在某些情况下,性能比任务快得令人难以置信,甚至比迭代器还要快(特别是Continuables.cmap的简单实现比Iterators.imap快一个数量级)。有关更多细节,请查看github存储库的Readme.md https://github.com/schlichtanders/Continuables.jl。
编辑:为了更直接地回答我自己的问题,没有必要使用宏@asiterator,只需直接使用延续样式。
mycontinuable(as::Array) = cont -> begin
b = 1
for (a1, a2) in zip(as, as[2:end])
try
cont(a1[1] + a2[2] + b)
catch exc
end
end
end
mycontinuable([(1,2), (3,1), 3, 4, (1,1)]) do i
@show i
endhttps://stackoverflow.com/questions/43575697
复制相似问题