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上实现的方式