我正在尝试剖析和理解
acc/0
和 reducer/0
在可枚举协议中如何工作。
def map(enumerable, fun) do
reducer = fn x, acc -> {:cont, [fun.(x) | acc]} end
Enumerable.reduce(enumerable, {:cont, []}, reducer) |> elem(1) |> :lists.reverse()
end
有人可以从每个枚举中的 x, acc 值开始解释这一点吗
Enum.reduce/3
,以及其他函数语言中类似的“减少”或“折叠”操作。 Enumerable
是一个较低级别的 Elixir 协议(接口),类型可以实现它来表示它们是“容器”,并且可以与 Enum
函数一起使用; reduce
是核心构建块。
reducer
参数将为列表中的每个元素调用一次,累加器的前一个(或初始)值作为该参数。 累加器参数的 Enumerable:acc/0
类型不仅包括值,还包括一个控制原子,它告诉 Enumerable
实现要做什么,特别是提供提前停止的选项。 :cont
这里的意思是“继续”,在这个例子中你将始终迭代整个列表。
假设您打电话
map([1, 2, 3], &(&1 * 2))
那么内部调用的顺序就是
reducer.(1, []) # {:cont, [2]}
reducer.(2, [2]) # {:cont, [4, 2]}
reducer.(3, [4, 2]) # {:cont, [6, 4, 2]}
剩余的逻辑分离
:cont
标记并反转列表,使其处于正确的顺序。