タイトルで言い切ってますが、Enum.reverse()の実態は :lists.reverse/1 です。
Erlang(結果として Elixir も)のリストは片方向リストのため、リストに値を追加する場合は、このような感じで先頭に追加して、最後に反転させるのがセオリーだそうです。
UPDATE: 例を直しました。
> A = [1|[]].
> B = [2|B].
> C = [3|C].
> C.
[3,2,1]
> lists:reverse(C).
[1,2,3]
この lists:reverse/1 関数は BIF(組み込み関数)としてCで実装されているため、非常に速いようです(そのうちベンチしたい。。。)。
で、Elixir ではどうなっているのか調べてみたところ、そもそも Elixir の List モジュールには reverse に該当する関数がありません。
まさか :lists.reverse([3,2,1])
のようにして Erlang の関数を直接呼ぶ必要があるのか? と一瞬思いましたが、そんなことはありませんでした。理由は定かではありませんが、List ではなく Enum の中に Enum.reverse
という関数がありました(arity は 1 と 2)。
Elixir 版もちゃんと BIF になってるのかと思い実装を見てみたところ、 lib/elixir/lib/enum.ex でこのように実装されていました。。。
@spec reverse(t) :: list
def reverse(enumerable) when is_list(enumerable) do
:lists.reverse(enumerable)
end
結局 :lists.reverse/1
を直接呼んでいるだけなので、結果として BIF で実装されていると言えます。
というわけで、リストに要素を追加する時は Erlang と同様に、先頭に要素を追加していき、最後に Enum.reverse/1
を呼べばいいということがわかりました。