为了理解为什么累加和反转非常快,您必须了解列表是如何在 Erlang 中构建的。像 Lisp 中的那些 Erlangs 列表是由 cons cells 构建的(查看链接中的图片)。
在像 Erlang 列表这样的单链表中,预先添加一个元素(或 短 列表)非常便宜。这就是 List = [H|T] 构造所做的。
反转由 cons 单元组成的单链表非常快,因为您只需要遍历列表,只需将下一个元素添加到您已经反转的部分结果。正如已经提到的,它也是在 Erlang 中用 C 语言实现的。
通常也可以通过尾递归函数来构建反向顺序的结果,这意味着不会构建堆栈并且(仅在旧版本的 Erlang 中!)因此可以节省一些内存.
说了这么多:这是The Eight Myths of Erlang Performance 之一,在尾递归函数中反向构建并在最后调用lists:reverse/1 总是更好。
这是一个没有lists:reverse/1 的正文递归版本,这将在 12 之前的 Erlang 版本上使用更多内存,但在当前版本上不会如此:
map([H|T], Fun) ->
[ Fun(H) | map(T,Fun) ];
map([],_) -> [].
这是一个使用列表推导的地图版本:
map(List, Fun) ->
[ Fun(X) || X <- List ].
如您所见,这非常简单,因为map 只是列表推导的内置部分,因此您可以直接使用列表推导,而不再需要map。
作为一个额外的纯 Erlang 实现,它显示了如何有效地反转 cons 单元列表(在 Erlang 中,调用 lists:reverse/1 总是更快,因为它是在 C 中,但做同样的事情)。
reverse(List) ->
reverse(List, []).
reverse([H|T], Acc) ->
reverse(T, [H|Acc]);
reverse([], Acc) ->
Acc.
如您所见,列表中只有 [A|B] 操作,将 cons 单元分开(在模式匹配时)并在执行 [H|Acc] 时构建新单元。