Erlang入門

Erlang本を入手したので学んでみる。

インストール

debianだとパッケージが用意されている。
# apt-get install erlang erlang-man

erlang-manは以下のようにモジュールを調べられるようになる。
$ erl -man lists

基本

_や大文字で始まるのが変数。_は/dev/nullみたいな変数。
小文字で始まるのがアトム。(アトムとはシンボル定数のようなもの)

=はマッチングして代入する演算子。(ちなみに変数への再代入はできない)

タプル
用途や型の異なるオブジェクトをひとまとまりにする。{}で定義。
リスト
要素内の型を同一なものにそろえる。[]で定義。

例:

1> Point = {point, 20, 30}.
2> {point,X,Y} = Point.
3> X.
20
4> Y.
30
リスト

カンマで区切る
[1,2,3,4]

こうも定義できる。
[1,2 | [3,4] ]

の左側がヘッド(先頭の要素)。右側がテール(ヘッド以外のリスト)。
リスト内包表記

リストを作成する式
[構築子||ジェネレータ or フィルター, ...]

構築子
要素を作る式
ジェネレータ
Pattern <- リスト。リストの中でPatternに一致するものが渡される。
フィルター
ブール式。ブール式がtrueの場合に渡される。

例:

1> Buy = [{[100,200,250],fruit},{[100],fish}].
2> [{lists:sum(A),B} || {A,B} <- Buy, B =:= fruit].
[{550,fruit}]

モジュール

.erlに書く。コンパイルすると.beamになる。

とりあえずサンプルで能力が均等になるようにチーム分けするプログラムを書いてみた。
(AoEとかのチームネット対戦ゲーで使うやつ)

以下でコンパイルして実行する。

1> c(team)
2> team:divide([3,4,5,2,6,6]).
[{0,[{1,3},{2,4},{5,6}],[{3,5},{4,2},{6,6}]},
 {0,[{3,5},{4,2},{5,6}],[{1,3},{2,4},{6,6}]},
 {2,[{1,3},{2,4},{3,5}],[{4,2},{5,6},{6,6}]},
 {2,[{1,3},{2,4},{3,5},{4,2}],[{5,6},{6,6}]},
 {2,[{1,3},{3,5},{5,6}],[{2,4},{4,2},{6,6}]}]

とりあえず候補を5つまで表示するようにしている。
入力のリストは各プレイヤーの能力を数値化したもの。
結果の1行目はPlayer1 Player2 Player5 vs Player3 Player4 Player6
で、チームの能力差0という意味である。
もっと短く書けるのかもしれないが、、、
再帰は慣れんなー、と思ってググってみるとこんなページを見つける。

Schemerはこう考える。
* 「一個前はなんだっけ」
* 「終わりはなんだっけ」

K&Rを読もう(8) 1.7 図解Schemerの再帰脳 - ボクノス

なるほど。

Erlangの大きな特徴の1つとして、分散アプリケーションを簡単に書けるというのがあるが、その辺りはまた後日。。。

team.erl
-module(team).
-export(divide/1).

pickup(_,0) -> [];
pickup(L,1) -> [H|_]=L, [H];
pickup(L,N) -> [H|T]=L, pickup([H],N rem 2) ++ pickup(T,N div 2).

pow(_,0) -> 1;
pow(N,M) -> N * pow(N,M-1).

pickuplist(_,0) -> [[]];
pickuplist(L,N) -> [pickup(L,N)] ++ pickuplist(L,N-1).

dividelist(L) -> [{A,L--A}||A <- pickuplist(L,pow(2,length(L)-1)-1)].

sum_level([]) -> 0;
sum_level(L) -> [{_,X}|T]=L,X+sum_level(T).

divide_leveled_list(L) ->
    [{abs(sum_level(A)-sum_level(B)),A,B}||
        {A,B}<-dividelist(L)].

sort_leveled_list(L) ->
    lists:sort(fun({X,_,_},{Y,_,_}) -> X<Y end,
               divide_leveled_list(L)).

numbering([],_) -> [];
numbering(L,N) -> [H|T]=L,[{N,H}]++numbering(T,N+1).

divide(L) -> lists:sublist(sort_leveled_list( numbering(L,1) ),5).

参考文献

プログラミングErlang

プログラミングErlang

続き:Erlang入門 その2 - 玲瓏庵