ぐらめぬ・ぜぷつぇんのはてダ(2007 to 2011)

2007年~2011年ごろまで はてなダイアリー に書いてた記事を引っ越してきました。

Listは配列か?

PHP勉強会 SIDE-B 第1回 発表資料 - ぐらめぬ・ぜぷつぇんのはてダErlangの資料で、Listのことを「いわゆる配列」と紹介した為、コメント欄でmakingxさんより

Erlangを触ったことないですがlistを”いわいる配列”というのは違和感を感じます,,
PHPの配列”なら納得ですがw

と突っ込みが。
そして早速id:hnwさんがコメント。

PHPの配列とは余計にかけ離れてる気がしますけど、どんな意味で違和感があるんでしょう?僕の理解では、linked listだよなー、Lisp系と違ってtupleとの関係がよくわかんないなー、というくらいの理解ですが。

更に「初Erlangですが」と速攻でコードexampleの掲示

まず、表現が曖昧だったことをお詫びします。m(__)m

ErlangのListは固定長である、というのが自分の現段階での理解です。Erlangは一度変数名に値を束縛したらもう変更できないので、Listも当然、一度

 L1 = [1, 2, ... ].

と束縛してしまえば、もうL1の値(=リストの要素)に新しい値を追加したり、あるいはあるindex位置の要素を削除したりとかはできません。
そういう意味では、JavaのArrayやCの配列、つまり最初に要素数を決定してしまえばそのサイズは固定されるタイプと似ていると思います。JavaのListやPHPの配列操作関数(array_push, array_pop, array_(un)shift)などは既存の配列に対して要素の追加・削除を操作できますが、Erlangでは出来ません。

じゃぁどうやってやるの?ですが・・・

先頭への要素の追加

まずListの先頭への要素の追加についてはErlangの言語仕様としてサポートされています。

12> L1 = [1, 2, 3].
[1,2,3]
13> L2 = [4 | L1].
[4,1,2,3]
14> b().
L1 = [1,2,3]
L2 = [4,1,2,3]
ok

line13の、"|"が先頭への要素追加の部分です。"|"の左側が追加する値、右側が対象Listです。
で、line14でerlシェルコマンドであるb()*1の結果に注目ですが、L1も要素の値とか変わらずにそのまま残っています。で、要素を追加したListは新しくL2という名前に束縛されています。

もうちょっとやってみると、

15> [ 1 | [1, 2, 3] ].
[1,1,2,3]

16> [ [1, 2] | [ 3, 4 ] ].
[[1,2],3,4]

17> [ [1, 2, 3] | 4 ].
[[1,2,3]|4]

line16に見るように、左側もListだった場合は、Listがmergeされたりはせず、左側のListが丸ごと要素として[3, 4]の先頭に追加されるイメージになるようです。
line17が謎ですね。

末尾への要素の追加

上のコード例のline17にみるように、"|"の後ろに要素を入れて楽しよう・・・というのは出来ないようです。こんな処理が必要になるようです。

-module(my_list_push).
-export([push/2]).

push([], E) -> [E];
push([H|T], E) -> [H | push(T, E)].

実行してみます。

1> c(my_list_push).
{ok,my_list_push}

2> L1 = [1, 2, 3].
[1,2,3]

3> my_list_push:push(L1, 4).
[1,2,3,4]

4> L1.
[1,2,3]

ここでもやっぱり、わざわざ新しいListを生成してます。で、ちゃんと元のListは変わらずにあります。

ちなみに、例えば「2番目の要素の値を変更したい」とかはどーするんでしょーか・・・。単純にErlangの原則に則れば、やっぱりそういうロジックを組みなり、listsモジュールのsplitあたりを駆使して、ちょうど文字列の操作のように行うんでしょうか・・・というのはまぁ後々勉強してれば出てくるでしょうから今は置いておきます。

えーと、つまり、ErlangのListは固定長で変更不可の配列と見なすことが可能です。変更不可ですので、要素の追加・削除・変更はロジックにより新しい配列を生成する必要があります。
そのため、PHPの配列とは大分異なると考えています。まぁ資料を作成した時点ではそこまで突っ込んでいなかったので曖昧な表記になってしまいましたが、少なくとも「PHPの」配列と特定しなかったのは結果としてセーフでした。

まぁErlangのListはどう頑張ってもErlangのListでしか無いわけで、「PHPでいうところの〜」とか「○○言語でいうところの〜」というのは全く知らない初めての人用に精神障壁を下げる為の方便でしかないわけです。

*1:現在束縛中の変数の一覧を表示