Apologies, this is not generally true and potentially bad advice.
First of all, it performs a double traversal: one on reduce, another on reverse (which is optimized in C). It is classic tail recursion.
Second, for
can perform map+filtering+flattening in one step, so as soon as you start piping into multiple Enum and Stream, for
should win by considerable margins.
The only case where for
is faster is when you are using it only for filtering or mapping a single list. And when we do so, the margins are very thin, as explained in Fred’s article.
In other words, for
can be considerably faster in several use cases, and slower by thin margins in one case.
As far as I know, Erlang does not perform this. It generally eliminates stack frames as part of body recursion but it does not perform any special behaviour for lists. Looking at the BEAM assembly I see no hints for this either:
bar([H | T]) -> [H * 2 | bar(T)];
bar([]) -> [].
{function, bar, 1, 2}.
{label,1}.
{line,[{location,"foo.erl",4}]}.
{func_info,{atom,foo},{atom,bar},1}.
{label,2}.
{test,is_nonempty_list,{f,3},[{x,0}]}.
{get_list,{x,0},{x,1},{x,0}}.
{gc_bif,'*',{f,0},2,[{x,1},{integer,2}],{x,1}}.
{allocate,1,2}.
{move,{x,1},{y,0}}.
{call,1,{f,2}}. % bar/1
{'%',{var_info,{x,0},[{type,{t_list,number,nil}}]}}.
{test_heap,2,1}.
{put_list,{y,0},{x,0},{x,0}}.
{deallocate,1}.
return.
{label,3}.
{test,is_nil,{f,1},[{x,0}]}.
return.
However, my knowledge may be out of date. Maybe the JIT performs new tricks? So pointers will be appreciated in such case.