Erlang:可以不使用list:reverse吗?

| 我是学习Erlang的初学者。在阅读完有关Erlang的列表推导和递归之后,我想尝试实现自己的
map
函数,结果如下所示:
% Map: Map all elements in a list by a function
map(List,Fun) -> map(List,Fun,[]).
map([],_,Acc) -> lists:reverse(Acc);
map([H|T],Fun,Acc) -> map(T,Fun,[Fun(H)|Acc]).
我的问题是:通过递归函数建立一个列表,然后在最后将其反向,这是错误的。有什么方法可以按正确的顺序建立列表,所以我们不需要相反的顺序?     
已邀请:
        为了了解为什么累积和反转非常快,您必须了解如何在Erlang中构建列表。像Lisp中的列表一样,Erlangs列表是由cons单元构建的(请看链接中的图片)。 在像Erlang列表这样的单链列表中,在元素前添加一个元素(或简短列表)非常便宜。这是the2ѭ构造所做的。 反转由cons单元格组成的单链接列表的速度非常快,因为您只需要沿列表一次通过,只需将下一个元素放在已反转部分结果的前面即可。就像已经提到的,它也在Erlang的C语言中实现。 通常,也可以通过尾部递归函数来以相反的顺序生成结果,这意味着不会建立堆栈,并且(仅在旧版本的Erlang中!)因此可以节省一些内存。 话虽如此,这是Erlang性能的八个神话之一,在尾部递归函数中反向构建并最后调用and3ѭ总是更好。 这是没有
lists:reverse/1
的主体递归版本,它将在12之前的Erlang版本上使用更多的内存,但在当前版本上不会使用更多的内存:
map([H|T], Fun) ->
    [ Fun(H) | map(T,Fun) ];
map([],_) -> [].
这是使用列表推导的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]
时新建一个。     
         这样的结构[元素| Acc],然后列出:reverse(Acc)是函数编程中非常普遍的模式。 您可以使用按正确顺序存储数据的累加器来编写代码,但是此代码将比问题中的代码慢(提示:使用Acc ++ [Fun(H)])。 实际上在Erlang list:reverse中是用C实现的,并且运行非常快。     

要回复问题请先登录注册