Elixir 长生不老药如何保存蓄电池

Elixir 长生不老药如何保存蓄电池,elixir,Elixir,我在试着理解长生不老药流。 首先,我有一个列表,它遍历一个范围并乘以2 iex(5)> stream = 1..3 |> ...(5)> Enum.map(&IO.inspect(&1)) |> ...(5)> Enum.map(&(&1 * 2)) |> ...(5)> Enum.map(&IO.inspect(&1)) |> ...(5)> Enum.reduce(4,

我在试着理解长生不老药流。
首先,我有一个列表,它遍历一个范围并乘以2

iex(5)>   stream = 1..3 |>
...(5)>   Enum.map(&IO.inspect(&1)) |>
...(5)>   Enum.map(&(&1 * 2)) |>
...(5)>   Enum.map(&IO.inspect(&1)) |>
...(5)>   Enum.reduce(4, &+/2)
1
2
3
2
4
6
16
这里一切都很清楚,每个枚举返回一个列表,以便进一步处理该列表。它对列表中的每个元素迭代四次。
让我们用流来构建它:

iex(4)>   stream = 1..3 |>
...(4)>   Stream.map(&IO.inspect(&1)) |>
...(4)>   Stream.map(&(&1 * 2)) |>
...(4)>   Stream.map(&IO.inspect(&1)) |>
...(4)>   Enum.reduce(4, &+/2)
1
2
2
4
3
6
16
在这里,它只对范围内的每个数字迭代一次,与上面使用enum的示例不同。我不明白的是,Enum.reduce的累加器在只迭代一次的情况下,如何保留该值并自行进行递归调用?
当我迭代枚举时,如下所示:

iex(25)> f = fn(x, y) ->
...(25)> IO.puts(y)
...(25)> x + y
...(25)> end
#Function<12.54118792/2 in :erl_eval.expr/5>
iex(26)> iter = 1..5 |> Enum.reduce(4, f)
4
5
7
10
14
19
iex(25)>f=fn(x,y)->
…(25)>IO.puts(y)
…(25)>x+y
…(25)>结束
#作用
iex(26)>iter=1..5 |>Enum.reduce(4,f)
4.
5.
7.
10
14
19
然后我可以想象,如何enum.reduce将累加器传递给下一个递归调用


但是,如果逐流迭代只执行一次,那么流如何传递下一个递归调用的累加器呢?

不确定您遗漏/询问的是什么,但让我尝试解释一下。首先,您必须知道流是如何工作的,并且在Elixir中是如何表示的:流只是对可枚举项进行操作的一组函数。当您编写流(例如,
1..3 |>Stream.map(…)|>Stream.map(…)
)时,您没有对流做任何“具体”的操作,您只是将函数添加到将用于处理初始可枚举项的函数列表中。当使用流调用
Enum.reduce/3
时,即开始迭代可枚举项(一次一个元素)

也可以通过检查
Enum.reduce/3
的进度来更好地理解您的示例:

iex> printer1 = fn el -> IO.puts "1st iteration, el: #{inspect el}"; el end
iex> printer2 = fn el -> IO.puts "2nd iteration, el: #{inspect el}"; el end
iex> reducer = fn el, acc ->
...>   IO.puts "reducing, el: #{inspect el}, acc: #{inspect acc}\n"
...>   el + acc
...> end
iex> 1..3 |> Stream.map(printer1) |> Stream.map(&(&1 + 10)) |> Stream.map(printer2) |> Enum.reduce(0, reducer)
1st iteration, el: 1
2nd iteration, el: 11
reducing, el: 11, acc: 0

1st iteration, el: 2
2nd iteration, el: 12
reducing, el: 12, acc: 11

1st iteration, el: 3
2nd iteration, el: 13
reducing, el: 13, acc: 23

36
如您所见,几乎没有什么神奇的事情发生:当我们调用
Enum.reduce/3
时,流开始展开,我们遍历映射三个函数的每个元素,并对其和累加器调用
reducer

它可以帮助您研究协议的文档,因为该协议用于从流中获取元素(通常一次一个)。当您链接
Enum.map/2
操作时(就像您在第一个示例中所做的那样),
Enum.reduce/3
将收到一个列表作为其第一个参数,因此将使用列表的
Enumerable
协议:它的实现只是在列表上迭代,并将列表的元素“产生”到
Enumerable.reduce
,一次一个。当您链接
Stream.map/2
操作时,
Enum.reduce/3
将接收一个流,因此将使用流的
Enumerable
协议:它的实现将每个元素从原始可枚举中取出(
1..3
),应用流操作(本例中为
Stream.map/2
链),并一次生成一个结果


希望我已经把事情说得更清楚了,如果你还有疑问,请问任何问题:)。

不确定你遗漏了什么/问了什么,但让我试着解释一下。首先,您必须知道流是如何工作的,并且在Elixir中是如何表示的:流只是对可枚举项进行操作的一组函数。当您编写流(例如,
1..3 |>Stream.map(…)|>Stream.map(…)
)时,您没有对流做任何“具体”的操作,您只是将函数添加到将用于处理初始可枚举项的函数列表中。当使用流调用
Enum.reduce/3
时,即开始迭代可枚举项(一次一个元素)

也可以通过检查
Enum.reduce/3
的进度来更好地理解您的示例:

iex> printer1 = fn el -> IO.puts "1st iteration, el: #{inspect el}"; el end
iex> printer2 = fn el -> IO.puts "2nd iteration, el: #{inspect el}"; el end
iex> reducer = fn el, acc ->
...>   IO.puts "reducing, el: #{inspect el}, acc: #{inspect acc}\n"
...>   el + acc
...> end
iex> 1..3 |> Stream.map(printer1) |> Stream.map(&(&1 + 10)) |> Stream.map(printer2) |> Enum.reduce(0, reducer)
1st iteration, el: 1
2nd iteration, el: 11
reducing, el: 11, acc: 0

1st iteration, el: 2
2nd iteration, el: 12
reducing, el: 12, acc: 11

1st iteration, el: 3
2nd iteration, el: 13
reducing, el: 13, acc: 23

36
如您所见,几乎没有什么神奇的事情发生:当我们调用
Enum.reduce/3
时,流开始展开,我们遍历映射三个函数的每个元素,并对其和累加器调用
reducer

它可以帮助您研究协议的文档,因为该协议用于从流中获取元素(通常一次一个)。当您链接
Enum.map/2
操作时(就像您在第一个示例中所做的那样),
Enum.reduce/3
将收到一个列表作为其第一个参数,因此将使用列表的
Enumerable
协议:它的实现只是在列表上迭代,并将列表的元素“产生”到
Enumerable.reduce
,一次一个。当您链接
Stream.map/2
操作时,
Enum.reduce/3
将接收一个流,因此将使用流的
Enumerable
协议:它的实现将每个元素从原始可枚举中取出(
1..3
),应用流操作(本例中为
Stream.map/2
链),并一次生成一个结果


希望我已经把事情说清楚了,如果你还有疑问,请问我:).

您的问题非常混乱-没有那么复杂看看您可以在GitHub中使用Elixir语言并查看源代码,尽管它可能是来自Erlang的映射。您的问题非常混乱-没有那么复杂看看您可以在GitHub中使用Elixir语言并查看源代码尽管它可能是来自Erlang的映射。当流逐个传递值时,没有指向下一个值的指针。当我仅使用
Enum.map
时,它将作为列表的中间部分,并且列表将从过去转到下一个
Enum.map
,该列表始终有一个指向下一个值的指针。当我使用流时,只会传递一个值,
Enum.map
如何知道下一个值的指针?你知道我的意思吗?@zero_编码不,我不确定你的意思:|如果我正确理解你的疑问,你就不确定流如何跟踪它在可枚举中的位置。我的建议(如回答中所述)是研究
可枚举协议:我们在enu上实现的方式