首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >朱莉娅中有一个宏可以从类似生成器的函数中创建快速迭代器吗?

朱莉娅中有一个宏可以从类似生成器的函数中创建快速迭代器吗?
EN

Stack Overflow用户
提问于 2017-04-23 19:42:53
回答 3查看 357关注 0票数 12

从python3到Julia,人们都希望能够将快速迭代器作为一个函数编写,并具有生成/输出语法或类似的功能。

julia的宏似乎表明,可以构建一个宏,将这样的“生成器”函数转换为julia迭代器。[您甚至可以轻松地使用函数样式编写内联迭代器,这是Iterators.jl包还试图为其特定的迭代器https://github.com/JuliaCollections/Iterators.jl#the-itr-macro-for-automatic-inlining-in-for-loops提供的特性]

举一个例子说明我的想法:

代码语言:javascript
复制
@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的任务完成的,至少据我所知。然而,它们似乎也比纯迭代器慢得多。例如,如果您可以使用简单的迭代器(如imapchain等)来表示您的函数(由Iterators.jl包提供),这似乎是非常可取的。

从理论上讲,朱莉娅是否有可能将生成函数转换为灵活的快速迭代器?

额外的问题:如果这是可能的话,是否会有一个通用的宏来内联这样的迭代器?

EN

回答 3

Stack Overflow用户

发布于 2017-05-04 23:11:24

此表单的一些迭代器可以如下所示:

代码语言:javascript
复制
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宏,执行您所描述的。但我不确定是否值得为朱莉娅这么做。

票数 4
EN

Stack Overflow用户

发布于 2017-04-25 16:34:03

朱莉娅中的Python风格的生成器- which最接近于从- involve任务中产生相当数量的固有开销。您必须切换任务,这是不平凡的,不能直接被编译器淘汰。这就是为什么Julia的迭代器基于转换一个典型不变的、简单的状态值和另一个的函数。长话短说:不,我不相信这种转变是可以自动完成的。

票数 2
EN

Stack Overflow用户

发布于 2017-05-18 16:53:54

在考虑了如何在不影响性能的情况下将python生成器转换为Julia之后,我实现并测试了一个高级函数库,该库以延续风格实现类似Python/任务的生成器。https://github.com/schlichtanders/Continuables.jl

本质上,我们的想法是将Python的yield /Julia的produce看作是我们从外部接受的一个额外的参数。我叫它cont是为了继续。例如,查看这个范围的重新实现。

代码语言:javascript
复制
crange(n::Integer) = cont -> begin
  for i in 1:n
    cont(i)
  end
end

您可以简单地用以下代码对所有整数进行求和

代码语言:javascript
复制
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,只需直接使用延续样式。

代码语言:javascript
复制
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
end
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43575697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档