如何获取流的元素(Elixir)并保持流的状态?

时间:2017-02-23 14:30:40

标签: stream elixir

我喜欢Elixir溪流。特别是我有一个构造无限素数流的函数;您可以使用相应的Stream / Enum操作(分别为Enum.take(10_000)Enum.take_while(& (&1 < 1_000_000)))获取前1,000个或所有低于1,000,000的素数或其他任何素数。

但是假设我事先并不知道我需要多少素数。我到了某一点,我说,嘿,实际上需要另外一千个素数。有没有办法说,获取流的前10,000个元素,然后以某种方式保存生成的流对象,以便我可以按需获得下一个 1,000(当然反复)?

2 个答案:

答案 0 :(得分:4)

TL; DR 保存累加器,而不是“流。”

@Dogbert在评论中提供了强大的解决方案:StreamSplit软件包似乎完全符合所要求的内容。

为了历史,我的答案是:有许多Stream函数(都来自Stream.transform/4,这是一个通用的流实现,几乎可能需要的一切)可能做的伎俩。例如,考虑斐波纳契数。可以将它们实现为:

stream = Stream.iterate({1, 1}, fn {acc, i} ->
  {acc + i, acc}
end)
#⇒ #Function<61.36862645/2 in Stream.unfold/2>
stream |> Enum.take(5) 
#⇒ [{1, 1}, {2, 1}, {3, 2}, {5, 3}, {8, 5}]
current = stream |> Enum.take(5) |> List.last
#⇒ {8, 5}

如果您想继续获取数字:

#              ⇓⇓⇓⇓⇓⇓
Stream.iterate({8, 5}, fn {acc, i} ->
  {acc + i, acc}
end)

只需保持中间状态并将其作为初始值传递给您用于获取素数的流函数。我个人认为保持“尾巴”而不是累加器没有任何优势,但我可能肯定是错的。

答案 1 :(得分:1)

你对Streams有一个基本的误解。 Stream是关于创建函数组合的,这样您就可以对只有一次通过原始可枚举的枚举进行复杂处理。

很容易将Stream与服务混淆,并且通过足够的挖掘,您可以“暂停”Stream来创建类似的服务。但是,你真正想要的是Prime服务器。一旦你开始考虑“状态”,你应该考虑GenServer。