lists:foldl ⊇ lists:map ⊇ lists:foreach

lists:foldl、lists:map、lists:foreach どれもリストの各要素に対する操作だけど、どう使い分ければ良いんだろう。

リストの各要素に対して(戻り値なしで)何らかのアクションを行う必要がある場合はlists:foreachを使おう。 リストの各要素について何らかの計算を行う必要がある場合はlists:mapを使おう。 リストの各要素の値を累計する必要がある場合はlist:foldlかlist:foldrを使おう。 listsモジュールには他にもいくつかの手軽なループが提供されている。listsモジュールのドキュメントに目を通して何が使えるかということを知っておくとよいだろう。

なるほど。

lists:fold(l|r)
戻り値有り & 要素の集計を行う
lists:map
戻り値有り & 各要素に対し計算を行う
lists:foreach
戻り値無し & 各要素に(計算というよりは)アクションを起こす

lists:foldl、lists:map、lists:foreach のうち、 一つだけ無人島に連れていけるとしたら?

ボクは lists:foldl ちゃん!
lists:map も lists:foreach も lists:foldl を使って簡単に実装出来るよ!

my_lists.erl

-module(my_lists).
-compile(export_all).

%% lists:map を lists:foldl で実装
map_by_foldl(Fun, L) ->
    L1 = lists:foldl(fun(E, AccIn) ->
			[Fun(E)|AccIn] end, [], L),
    lists:reverse(L1).

%% lists:foreach を lists:foldl で実装
foreach_by_foldl(Fun, L) ->
    map_by_foldl(Fun, L),
    ok.

%% lists:foreach を lists:map で実装
foreach_by_map(Fun, L) ->
    lists:map(Fun, L),
    ok.

実行

> lists:map(fun(X) -> X * 2 end, L).
[2,4,6,8,10]
> my_lists:map_by_foldl(fun(X) -> X * 2 end, L).
[2,4,6,8,10]
> lists:foreach(fun(X) -> io:format("*~w*~n",[X]) end, L).
*1*
*2*
*3*
*4*
*5*
ok
> my_lists:foreach_by_foldl(fun(X) -> io:format("*~w*~n",[X]) end, L).
*1*
*2*
*3*
*4*
*5*
ok

わーい。おんなじだー >w<

lists:foldl ⊇ lists:map ⊇ lists:foreach なのかな。
逆向きはややこしいワイ。

ちなみに 本家の実装

/usr/local/lib/erlang/lib/stdlib-1.15.2/src/lists.erl

%% 中略
map(F, [H|T]) ->
    [F(H)|map(F, T)];
map(F, []) when is_function(F, 1) -> [].
%% 中略
foldl(F, Accu, [Hd|Tail]) ->
    foldl(F, F(Hd, Accu), Tail);
foldl(F, Accu, []) when is_function(F, 2) -> Accu.
%% 中略
foreach(F, [Hd|Tail]) ->
    F(Hd),
    foreach(F, Tail);
foreach(F, []) when is_function(F, 1) -> ok.

こっちのが断然スマート。