Erlang:列表理解,列表:map / 2,列表:foreach / 2使用

时间:2015-02-28 01:40:45

标签: erlang

列表理解和列表之间的效果:map / 2,后者的性能似乎比我的测试更好。

参考效率指南中关于列表理解的参考链接 用户指南:http://www.erlang.org/doc/efficiency_guide/listHandling.html#id66810

它说" 如果显然不会使用列表理解的结果,则不会构建列表。"

问题:我想知道列表:map / 2' s结果如何不使用(比如list:foreach / 2),它是否与列表理解相同& #34;不会构建列表" ??

2 个答案:

答案 0 :(得分:2)

检查这一点的一种方法是编写一个以明显无用的方式使用lists:map/2的函数,然后跟踪它。考虑这个功能:

map() ->
    dbg:tracer(), dbg:p(self(), call),
    dbg:tpl(lists,map,c),
    lists:map(fun(X) -> X end, []),
    dbg:stop_clear().

如果你在模块x中实现这个功能,编译它,然后在shell中产生一个对它的调用(spawn消除了shell本身引起的跟踪消息),你会看到如下内容:

3> spawn(x,map,[]).
<0.45.0>
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[]) ({lists,map,2})
(<0.45.0>) call lists:map(#Fun<x.0.133743400>,[]) ({x,map,0})
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[nonode@nohost]) ({dbg,
                                                                   do_ctp,2})
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[]) ({lists,map,2})
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[nonode@nohost]) ({dbg,
                                                                   do_ctp,2})

从跟踪输出的第三行可以看出,调用了匿名函数#Fun<x.0.133743400>,这是我们x:map/0函数中的匿名函数,调用者是{x,map,0},更好地称为x:map/0。 (所有其他跟踪消息都是由我用于跟踪的dbg模块的调用引起的。)

另一种方法是使用-S编译器的erlc选项编译到程序集。首先取消dbg来电:

map() ->
    lists:map(fun(X) -> X end, []).

然后使用-S进行编译并查看结果:

{function, map, 0, 4}.
  {label,3}.
    {line,[{location,"x.erl",8}]}.
    {func_info,{atom,x},{atom,map},0}.
  {label,4}.
    {make_fun2,{f,15},0,0,0}.
    {move,nil,{x,1}}.
    {line,[{location,"x.erl",9}]}.
    {call_ext_only,2,{extfunc,lists,map,2}}.

这里的重要行是最后一个,{move,nil,{x,1}}.,它将空列表移动到VM寄存器中作为参数传递,最后一行是lists:map/2的调用

根据使用Erlang 17.4构建的这些结果,可以肯定地说你问题的答案是否定的。

答案 1 :(得分:1)

lists:map/2是一个已经在你的系统中编译过的函数,实际上要点是它是在一个单独的模块中编译的,你的代码,所以编译器不能生成关于结果的使用与否的任何假设。 list comprehension在您的代码中编译,因此可以执行优化

[编辑] 抱歉,我没有重新检查,列表:地图已写:

map(F, [H|T]) ->
    [F(H)|map(F, T)];
map(F, []) when is_function(F, 1) -> [].

不是列表理解!