4

问题:是否有可能创建一个 Elixir Stream,在内部保持某种状态,每次调用都会改变?代码看起来如何?

我很高兴看到 Elixir 0.10.2Stream除了普通Enum模块之外还有 s。虽然有关于如何使用Streams 的文档,但几乎没有文档或描述如何创建它们的全局可搜索文档。阅读Stream模块的源代码并不是很有启发性。我还研究了 Lazily 连接一个可枚举的列表及其答案,虽然非常有趣,但它也没有涉及改变状态。

考虑在需要记住前两个值的地方生成斐波那契数。或者想想Clojure 的素数惰性序列

我首先理解这是否可能的问题是:

  1. 记录的enumerable元素仅由一些示例设置,并且始终设置为现有的固定列表。处理无限序列的示例根本不涉及enumerable(例如iterateor repeat)。
  2. 提供的函数fun应该返回另一个函数,而不是新Stream.Lazy记录,据我所知,这与 Clojure 的惰性序列有很大的不同,在这种惰性序列中,您使用lazy-seq.
  3. 累加器acc的使用方式仍然有些超出我的理解。看起来fun它本身并没有修改它;取而代之的是一些调用dos的外部函数fun

因此我的问题。

4

3 回答 3

3

Stream.unfold/2允许您生成一系列值,同时保持“累加器”(状态)。

我刚刚在这里使用它构建了一个惰性斐波那契序列函数:https ://github.com/seven1m/30-days-of-elixir/blob/master/24-stream.exs#L31-33

于 2014-01-13T04:28:03.440 回答
1

我只是在小溪边玩。我可能错过了重点,但是为了维护状态,可以使用精确器(gen_server)吗?

https://github.com/sasa1977/exactor

定义

defmodule Sample do
  use ExActor

  defcall next(x), state: state, do: reply(state + x, x)

  def fib(n) do
    {:ok, act} = Sample.start(1)
    Stream.iterate(0, fn(x) -> Sample.next(act, x) end) |> Enum.take(n)
  end
end

iex(3)> Sample.fib(5) 
[0, 1, 1, 2, 3]
iex(4)> Sample.fib(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
于 2013-09-11T15:39:55.540 回答
1

我不是惰性流方面的专家,但这是我的尝试:https ://gist.github.com/sasa1977/6699577

但是请注意,在此示例中,状态是公开的,而不是内部的,所以我不知道这是否是您要查找的内容。

解决方案首先依赖于创建一个记录(在这种情况下是私有的),并公开一个可以将记录移动到下一个状态的函数:

fib0 = Fibonacci.new
fib1 = Fibonacci.next(fib0)
fib2 = Fibonacci.next(fib1)
fib3 = Fibonacci.next(fib2)
IO.inspect fib3

每个都fibx包含完整的状态。在这种情况下,我将保留当前数字以及之前生成的两个数字。

基于此,我现在可以Stream.iterate用来制作一个无穷无尽的惰性集合:

Fibonacci.lazy
|> Enum.take(5)
|> IO.inspect

由于它基于Fibonacci.next,因此每个生成的元素都是一条记录,而不是一个值。您可以使用Fibonacci.value从每个元素中提取值。

还可以执行更复杂的操作:

Fibonacci.lazy
|> Stream.drop(3)                                           # drop first three
|> Enum.first                                               # take the first
|> Fibonacci.lazy                                           # start lazy from it
|> Stream.filter(&(rem(Fibonacci.value(&1), 2) == 1))       # take only odd values
|> Stream.map(&(Fibonacci.value(&1)))                       # extract values from it
|> Enum.take(10)                                            # take first 10
|> IO.inspect                                               # print it
于 2013-09-25T13:42:52.930 回答