Erlang: List Comprehension, lists:map/2, lists:foreach/2 来使用
Erlang: List Comprehension, lists:map/2, lists:foreach/2 To use
List Comprehension 和lists 的效果:map/2,根据我的测试,后者的性能似乎更好。
参考 link 关于效率指南中的列表理解
用户指南:http://www.erlang.org/doc/efficiency_guide/listHandling.html#id66810
它说“如果显然不会使用列表理解的结果,则不会构造列表。”
问题: 请问lists:map/2不使用(like lists:foreach/2)的结果和list一样吗理解 "a list will not be constructed" ??
检查这一点的一种方法是编写一个以明显无用的方式使用 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 中生成对它的调用(生成消除了由 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})
从trace输出的第三行可以看出,调用了匿名函数#Fun<x.0.133743400>
,也就是我们x:map/0
函数内部的匿名函数,调用者是{x,map,0}
,更为人所知的是 x:map/0
。 (所有其他跟踪消息都是由我用于跟踪的 dbg
模块的调用引起的。)
另一种方法是使用 erlc
编译器的 -S
选项编译为汇编。首先消除 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 寄存器中作为参数传递,最后一行是对 [=14 的调用=].
根据这些使用 Erlang 17.4 构建的结果,可以肯定地说您的问题的答案是否定的。
lists:map/2
是一个已经在你的系统中编译的函数,其实重点是 它是在你的代码 的单独模块中编译的,所以编译器不得对结果的使用与否做出任何假设。列表理解是在您的代码中编译的,因此可以执行优化
[edit] sorry,我没有重新检查,lists:map写成:
map(F, [H|T]) ->
[F(H)|map(F, T)];
map(F, []) when is_function(F, 1) -> [].
不是列表理解!
List Comprehension 和lists 的效果:map/2,根据我的测试,后者的性能似乎更好。
参考 link 关于效率指南中的列表理解 用户指南:http://www.erlang.org/doc/efficiency_guide/listHandling.html#id66810
它说“如果显然不会使用列表理解的结果,则不会构造列表。”
问题: 请问lists:map/2不使用(like lists:foreach/2)的结果和list一样吗理解 "a list will not be constructed" ??
检查这一点的一种方法是编写一个以明显无用的方式使用 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 中生成对它的调用(生成消除了由 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})
从trace输出的第三行可以看出,调用了匿名函数#Fun<x.0.133743400>
,也就是我们x:map/0
函数内部的匿名函数,调用者是{x,map,0}
,更为人所知的是 x:map/0
。 (所有其他跟踪消息都是由我用于跟踪的 dbg
模块的调用引起的。)
另一种方法是使用 erlc
编译器的 -S
选项编译为汇编。首先消除 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 寄存器中作为参数传递,最后一行是对 [=14 的调用=].
根据这些使用 Erlang 17.4 构建的结果,可以肯定地说您的问题的答案是否定的。
lists:map/2
是一个已经在你的系统中编译的函数,其实重点是 它是在你的代码 的单独模块中编译的,所以编译器不得对结果的使用与否做出任何假设。列表理解是在您的代码中编译的,因此可以执行优化
[edit] sorry,我没有重新检查,lists:map写成:
map(F, [H|T]) ->
[F(H)|map(F, T)];
map(F, []) when is_function(F, 1) -> [].
不是列表理解!