2007/05/19

逆指値注文の特許

逆指値注文の特許があるとは。

特許第3875206号

それにしても請求項の記述が長いので、文字数を調べてみた。
 請求項1:1338文字
 請求項2:1647文字

がんばったなぁ。

2007/05/15

リースの資産計上

WBSで出ていたが、08年度からリースで借りた設備が資産計上されるのだそうだ。
これじゃあリースのメリットが一つなくなるな。
リース業界も再編らしい。

2007/05/13

erlang その10

続続続ets module
ets:matchの関連関数を使ってみる。

<ets_tut5.erl>

-module(ets_tut5).
-export([test/0]).


test()->
P = ets:new(test1, [bag]),
ets:insert(P, [{a,1,r},{b,2,s},{b,3,u},{b,4,u},{c,5,u}]),
io:format("~p~n", [ets:match_object(P, {'_','$1','$2'})]),
io:format("~p~n", [ets:match_object(P, {'_','_','_'})]),
io:format("~p~n", [ets:match_object(P, {'_','_','u'})]),
ets:delete(P).


結果は次のようになる。
157> c(ets_tut5).
{ok,ets_tut5}
158> ets_tut5:test().
[{c,5,u},{b,2,s},{b,3,u},{b,4,u},{a,1,r}]
[{c,5,u},{b,2,s},{b,3,u},{b,4,u},{a,1,r}]
[{c,5,u},{b,3,u},{b,4,u}]
true

パターンに一致した要素をそのまま取得できていることが確認できる。また、ets:matchで使えた $1 や $2 は _ と同様に解釈されるようである。

次に、match_object(Tab, Pattern, Limit) と match_object(Continuation) を使ってみる。この2つの関数はPatternに一致した要素のうち、Limit個ずつ結果として受け取るために使う。ここでは、Patternに一致した要素を引数で指定した関数で処理する関数を作ってみる。
<ets_tut6>
-module(ets_tut6).
-export([test/0]).


test()->
P = ets:new(test1, [bag]),
ets:insert(P, [{a,1,r},{b,2,s},{b,3,u},{b,4,u},{c,5,u}]),
X = foreach(P, {'b','_','_'},
fun(X)->io:format("~p~n", [X]) end),
ets:delete(P),
X.


foreach(P, Pattern, Fun)->
foreach(ets:match_object(P, Pattern, 1), Fun).


foreach(X, _) when X=='$end_of_table' ->ok;


foreach({Match, Cont}, Fun)->
lists:foreach(Fun, Match),
foreach(ets:match_object(Cont), Fun).


tupleの先頭の要素が b である要素を表示するようにしたので、
199> c(ets_tut6).
{ok,ets_tut6}
200> ets_tut6:test().
{b,4,u}
{b,3,u}
{b,2,s}
ok

という結果が得られる。

2007/05/11

erlang その9

続続ets module

ets:matchを使ってみる。
この関数はパターンに一致したtupleをテーブルから取り出す。
取り出される値はtupleそのものではなく、指定したtupleの要素のリストとなる。
形式的な定義はリファレンスマニュアルをみればわかるので、使用例を示す。
<ets_tut4.erl>

-module(ets_tut4).
-export([test/0]).


test()->
P = ets:new(test1, [bag]),
ets:insert(P, [{a,1,r},{b,2,s},{b,3,u},{b,4,u},{c,5,u}]),
io:format("~p~n", [ets:match(P, {'_','$1','$2'})]),
io:format("~p~n", [ets:match(P, {'_','$2','$1'})]),
io:format("~p~n", [ets:match(P, {a,'$1','_'})]),
io:format("~p~n", [ets:match(P, {b,'_','$1'})]),
io:format("~p~n", [ets:match(P, {'$1','_',u})]),
ets:delete(P).


これを実行すると、
1> c(ets_tut4).
{ok,ets_tut4}
2> ets_tut4:test().
[[5,u],[2,s],[3,u],[4,u],[1,r]]
[[u,5],[s,2],[u,3],[u,4],[r,1]]
[[1]]
[[s],[u],[u]]
[[c],[b],[b]]
true

となる。matchの第1引数はテーブル識別子で第2引数にパターンを指定する。
最初の出力で指定したパターンは
 {'_','$1','$2'}
であるが、これはPに格納されているtupleのうち、全ての要素が任意であることを示す。
つまり、Pに記録されているtupleが全て得られる。'_'はただ任意であることを示す。
一方、'$1'や'$2'は戻り値として得たい要素であることを示している。
'$1'に指定された要素は戻り値のリストの1番目の要素に記録され、'$2'は2番目に記録される。
したがって、得られる結果は
[[5,u],[2,s],[3,u],[4,u],[1,r]]
となる。

2つ目の出力で指定したパターンは最初のものと'$1'と'$2'の位置が入れ替わっている。
これは結果が先ほどのものと順序が逆になるということであり、
[[u,5],[s,2],[u,3],[u,4],[r,1]]
が得られる。

3つ目の出力で指定したパターンは{a,'$1','_'}である。
これはtupleの最初の要素がaであるもののみ取得することを示している。
したがって、最初の要素がaであるのは{a,1,r}であり、出力結果は
2番目の要素で構成されることになっているので、結果は
[[1]]
となる。

4つ目の出力で指定したパターンは{b,'_','$1'}である。
先ほどと同様の理由で、
[[s],[u],[u]]
が得られる。

テーブルのキーでない要素でも指定することができる。
5つ目の出力ではtupleの3番目の要素を指定する。パターンは{'$1','_',u}である。
uに一致するもののうち、最初の要素を集めるので、結果は、
[[c],[b],[b]]
となる。

2007/05/10

erlang その8

続ets module

ets:foldlとets:foldr関数を使ってみる。
lists:foldsとlists:foldrと同様だそうだ。

<ets_tut2.erl>

-module(ets_tut2).
-export([test/0]).


fold(Option)->
P = ets:new(test1,Option),
ets:insert(P,{a}),
ets:insert(P,{b}),
ets:insert(P,{c}),
CL = ets:foldl(fun(X, Con)->[X|Con] end, [{d}], P),
io:format("foldl ~p ~p~n", [Option, CL]),
CR = ets:foldr(fun(X, Con)->[X|Con] end, [{d}], P),
io:format("foldr ~p ~p~n", [Option, CR]),
ets:delete(P).


test()->
fold([]),
fold([ordered_set]).


実行結果は次のようになった。
1> c(ets_tut2).
{ok,ets_tut2}
2> ets_tut2:test().
foldl [] [{c},{b},{a},{d}]
foldr [] [{c},{b},{a},{d}]
foldl [ordered_set] [{c},{b},{a},{d}]
foldr [ordered_set] [{a},{b},{c},{d}]
true

Optionが空、つまりsetの場合は、foldlとfoldrの結果は同じになった。
一方、ordered setの場合は、foldlとfoldrの結果は異なった。

ordered setの場合、foldlは最初の要素から順に関数を実行していくので、
まず初期値[{d}]の前方に{a}が付けられる。したがって、[{a},{d}]となる。
つぎの要素は[{b}]なので、[{b},{a},{d}]となり、最後の要素の処理が終わると、
[{c},{b},{a},{d}]となる。
foldrの場合はその逆に動作するので[{a},{b},{c},{d}]となる。


次に、ets:lookupとets:lookup_elementを使ってみる。
<ets_tut3.erl>
-module(ets_tut3).
-export([test/0]).


test()->
lookup([set]),
lookup([ordered_set]),
lookup([bag]),
lookup([duplicate_bag]).


lookup(Option)->
P = ets:new(test1, Option),
ets:insert(P, [{a,10},{a,20},{a,20},{b,1},{b,5},{b,2}]),
io:format("~p ~p~n", [Option, ets:lookup(P,a)]),
io:format("~p ~p~n", [Option, ets:lookup(P,b)]),
io:format("~p ~p~n", [Option, ets:lookup_element(P,a,2)]),
io:format("~p ~p~n", [Option, ets:lookup_element(P,b,2)]),
ets:delete(P).


実行結果は次のようになった。
1> c(ets_tut3).
{ok,ets_tut3}
2> ets_tut3:test().
[set] [{a,20}]
[set] [{b,2}]
[set] 20
[set] 2
[ordered_set] [{a,20}]
[ordered_set] [{b,2}]
[ordered_set] 20
[ordered_set] 2
[bag] [{a,10},{a,20}]
[bag] [{b,1},{b,5},{b,2}]
[bag] [10,20]
[bag] [1,5,2]
[duplicate_bag] [{a,10},{a,20},{a,20}]
[duplicate_bag] [{b,1},{b,5},{b,2}]
[duplicate_bag] [10,20,20]
[duplicate_bag] [1,5,2]
true

lookupは第2引数で指定したキーに一致する要素一覧を取得する。
setとordered_setの結果は同じ。
bagは同じキーの重複は許されるが、内容が全て同じ要素の重複は許されない。
duplicate_bagはどのようなケースでも重複が許される。
そのため、キーaに対するbagとduplicate_bagの結果が異なっている。

lookup_elementの第3引数にはtupleの何番目の要素を取得するかを指定する。
ここでは2と指定したので、tupleの2番目の要素である数字のリストが得られる。

2007/05/09

erlang その7

ets:new とその関連関数を使ってみる。
これらの関数はテーブルを作成して、そこに色々な要素を記録しておくために使われるようだ。
C++のstd::mapの高機能版のようなものか?

まず、テーブルを作成する。
第1引数はテーブルの名前で、第2引数はオプションを指定する。[]でデフォルトが利用される。
Pにはテーブル識別子(マニュアルではtid()と記載されている)が代入される。
1> P=ets:new(table1,[]).
16

次にこのテーブルの情報を見てみる。
2> ets:info(P).
[{memory,279},
{owner,<0.30.0>},
{name,table1},
{size,0},
{node,nonode@nohost},
{named_table,false},
{type,set},
{keypos,1},
{protection,protected}]

マニュアルによるとmemory は 「The number of words allocated to the table.」
とのことなので、単位をbytesであるとはいえそうにない。
sizeはテーブルに記録されているオブジェクトの数で、今は空なので0になっている。

テーブルに要素を追加してみる。
3> ets:insert(P, {aaa}).
true

テーブルの情報をみると、
4> ets:info(P).
[{memory,289},
{owner,<0.30.0>},
{name,table1},
{size,1},
{node,nonode@nohost},
{named_table,false},
{type,set},
{keypos,1},
{protection,protected}]

となっており、要素数が1増えている。
さらに追加してみると、
5> ets:insert(P, {bbb}).
true
6> ets:info(P).
[{memory,299},
{owner,<0.30.0>},
{name,table1},
{size,2},
{node,nonode@nohost},
{named_table,false},
{type,set},
{keypos,1},
{protection,protected}]

要素数が2になった。また、memoryが10ずつ増えている。
もう少し短いatomを追加してみる。
7> ets:insert(P, {c}).
true
8> ets:info(P).
[{memory,309},
{owner,<0.30.0>},
{name,table1},
{size,3},
{node,nonode@nohost},
{named_table,false},
{type,set},
{keypos,1},
{protection,protected}]

要素数が3になり、memoryは前と同様に10増える。

要素を順番に見ていくには、ets:first/1とets:second/2を使う。
まずets:first/1を使って、
9> ets:first(P).
c

最初の要素はcのようだ。次にets:next/2を使って、
cの要素の次に記録されている要素を順次取得する。
10> ets:next(P,c).
aaa
11> ets:next(P,aaa).
bbb
12> ets:next(P,bbb).
'$end_of_table'

テーブルの最後までくると、'$end_of_table'が返される。
これで終端かどうかが判断できる。

ところで、このテーブルの機能は便利なのだが
テーブルに記録した値は変更できてしまうことになる。
使い方によってはC言語っぽい書き方ができてしまいそうだ。

また、ets.erlによると、これらetsモジュールの関数の一部、
例えばnewやfirst, nextの実装はC言語でされているとのことだ。

2007/05/08

erlang その6

ファイル名に.を含めてみる。
<ets.tut1.erl>

-module(ets.tut1).
-export([test/0]).
test()->io:format("~p~n", ["test"]).

これをコンパイルしてみると、
1> c(ets.tut1).
** Module name ''ets.tut1'' does not match file name ''ets.tut1'' **
{error,badfile}

となる。また試しに ' でくくってみた。
2> c('ets.tut1').
** 2: syntax error before: c **

やはりエラー。
どうやらファイル名を . を含めると正常に処理できないようだ。
リファレンスマニュアルによると
<引用>
The name Module, an atom, should be the same as the file name minus the extension erl.
</引用>
である。また、atomには . を含んでもよい。
このことから、ファイル名の途中に . を含めることができそうにみえるが、できないようだ。
マニュアルのどこかに別途この点について記載がされているのかもしれない…

2007/05/06

erlang その5

●正規表現ライブラリ regexp を使ってみる。

一致した位置を取得する関数 match を使ってみる。
最初の引数が処理対象の文字列で、第2引数が正規表現。
1> regexp:match("a,bc,def,123", ",").
{match,2,1}
結果の2番目が一致した位置で、この場合は最初の,が一致している位置なので、2になる。
0 originではなく、1 originである。
戻り値の最後の値は一致した文字数になので、1になる。

2> regexp:match("a,bc,def,123", ",d").
{match,5,2}
この例では2文字一致しているので戻り値の3番目の値が2になっている。

3> regexp:match("a,bc,def,123", ",d.f").
{match,5,4}
ピリオド.は任意の1文字に一致するので、,defが一致している。

4> regexp:match("a,bc,def,123", ",d.*2").
{match,5,7}
*は0個以上の文字に一致するので、.*で任意の0個以上の文字への一致を調べることになる。
なので、「,def,12」に一致することになり、一致した文字の長さは7文字になる。

マニュアルによるとmatchよりもfirst_matchを使用する方が速いとのこと。
使いかたは同じで、
5> regexp:first_match("a,bc,def,123", ",d.*2").
{match,5,7}

一致する部分を全てみつけたい場合は matches を使う。
6> regexp:matches("a,bc,def,123", ",").
{match,[{2,1},{5,1},{9,1}]}
コンマ,の場所を見付けているので、2文字目、5文字目, 9文字目が見つかる。

今度は、一致した場所の文字を置換する。置換には sub を使う。
この関数では最初に見つけた位置の文字を置き換えるだけ。
7> regexp:sub("a,bc,def,123", ",", " ").
{ok,"a bc,def,123",1}
返される結果の2番目は、置換処理後の文字列となっており、
最初のコンマがスペースに置き換えられている。

一致した場所全てを置き換えたい場合は gsub を使う。
8> regexp:gsub("a,bc,def,123", ",", " ").
{ok,"a bc def 123",3}
結果の3番目の値は置き換えた"箇所"の数で、この例ではコンマが3箇所あるので3になる。

一致した場所で文字列を分割する。これには split を使う。
9> regexp:split("a,bc,def,123", ",").
{ok,["a","bc","def","123"]}
コンマで分割された文字列のリストとして結果が返される。

今回はここまで。

2007/05/03

erlang その4

●ファイル
ファイルの入出力の方法について調べてみた。
まずは、ファイルからの読み込み。
<tut11.erl>

-module(tut11).
-export([read/1]).

read(FileName)->
Handle = file:open(FileName, read),
if element(1,Handle) /= ok -> element(1, Handle);
true -> show_content(element(2,Handle)),
file:close(element(2, Handle))
end.

show_content(Handle)->
Result = io:get_line(Handle, prompt),
if Result == eof -> ok;
true -> io:format("~p~n",[Result]),
show_content(Handle)
end.

さらにテスト用のファイルを作成する。
<test1.txt>
abc
def
123

コンパイルして、
6> c(tut11).
{ok,tut11}

実行すると、
7> tut11:read("test1.txt").
"abc\n"
"def\n"
"123\n"
ok

のような結果が得られる。
io:get_lineでは改行コードは除去されないようだ。

次にファイルへの書き出しを試してみる。
ついでにio:formatの~pと~wと~sの違いを見てみる。
<tut12.erl>
-module(tut12).
-export([write/2]).

write(FileName, Str)->
Handle = file:open(FileName, write),
if element(1,Handle) /= ok -> element(1, Handle);
true -> write_content(element(2,Handle), Str),
file:close(element(2, Handle))
end.

write_content(_, [])->ok;
write_content(Handle, [Head|Rest])->
io:format(Handle, "~p,~w,~s~n", [[Head],[Head],[Head]]),
write_content(Handle, Rest).

コンパイルして、
36> c(tut12).
{ok,tut12}

実行してみる。
41> tut12:write("test2.txt", ["abc"]).
出力されたファイルの内容は、
["abc"],[[97,98,99]],abc

つまり、
~p : 入力された内容をそのまま出力。
~w : 各文字を値として解釈
~s : 文字列として解釈
ということになるようだ。(詳しくはerlangのreference manualを参照のこと)

今度は、日本語に挑戦。
ただ、erlang shellは日本語を受け付けてくれないので、
UTF-8の文字コードを直接入力してみる。

42> tut12:write("test2.txt", [227,129,130]).
出力されたファイルの内容は、
"�",[227],
[129],[129],�
[130],[130],�

ん?各値ごとに出力しようとしているようだ。

["abc"]のようにするには、
46> tut12:write("test2.txt", [[227,129,130]]).
とすればよい。
この出力結果は、
[[227,129,130]],[[227,129,130]],あ

のようになる。~sの出力が日本語になっている。
むろん、UTF-8で日本語が表示できるUNIX shell等で表示させている。

erlang その3

●文字列に関して
Atomは文字で、小文字から始まらないorアルファベットか数字以外の文字で
構成されるときはシングルクォート'で囲まないといけない。

Stringはダブルクォート"で囲まれた文字。
Erlangのデータ型ではなく、Listとして表現される。

●Shellに関して
Shellで定義した変数を消去するには、f()を使うとよい。
1> X=1.
1
2> X=2.

=ERROR REPORT==== 2-May-2007::22:19:18 ===
Error in process <0.30.0> with exit value: {{badmatch,2},[{erl_eval,expr,3}]}

** exited: {{badmatch,2},[{erl_eval,expr,3}]} **
3> f().
ok
4> X=2.
2

さらに特定の変数の定義を除去することもできる。
5> Y=3.
3
6> X=3.

=ERROR REPORT==== 2-May-2007::22:20:08 ===
Error in process <0.33.0> with exit value: {{badmatch,3},[{erl_eval,expr,3}]}

** exited: {{badmatch,3},[{erl_eval,expr,3}]} **
7> Y=2.

=ERROR REPORT==== 2-May-2007::22:20:10 ===
Error in process <0.38.0> with exit value: {{badmatch,2},[{erl_eval,expr,3}]}

** exited: {{badmatch,2},[{erl_eval,expr,3}]} **

この時点で、X=3, Y=2となっている。
8> f(Y).
ok

これでYの定義のみが消去された。なので、
9> X=3.

=ERROR REPORT==== 2-May-2007::22:20:18 ===
Error in process <0.40.0> with exit value: {{badmatch,3},[{erl_eval,expr,3}]}

** exited: {{badmatch,3},[{erl_eval,expr,3}]} **

のように、Xは定義済みなので再定義できないが、Yについては先ほど消去しているので
10> Y=2.
2
のように再定義できる。

●erlangプログラムのコンパイル
いろいろ探してみたが、ネイティブコードを出力するコンパイラを見つけられない…

とりあえず、UNIXのshellから実行できるようにするには、
(1)コマンドラインから.erlファイルを実行
(2).erlプログラムの最後にhalt().を書いて、shellを止める
の2つを行うしかなさそうだ。

あんましよさげではないが、例えば
<tut10.erl>
-module(tut10).
-export([main/1]).
main(X)->io:format("~p~n",[X]),
     halt().

のようなファイルを作成し、
UNIX> erl -compile tut10.erl

としてコンパイルして、
UNIX> erl -noinput -run tut10 main abc
["abc"]

のようにして実行する。ちなみに日本語を入れると、
UNIX> erl -noinput -run tut10 main あ
[[227,129,130]]

となり、日本語の出力ができない。
データの値からしてUTF-8でエンコードされているようだ。
なので、ファイルにバイナリで出力できれば読めそう。

erlang shell や UNIX shell に日本語を出力する方法は見つけられず…

2007/05/01

erlang その2

今度は、標準モジュールの説明。
マニュアルはコマンドラインから
# erl -man io
で見ることができる。この場合は、ioモジュールのマニュアルが表示される。
これはerlangのシェルからではなく、csh等の通常のシェルから実行する。

# io:format("test~n").
test
ok
# io:format("test~n", []).
test
ok

引数なしでも空リスト引数でも表示できる。

# io:format("test ~w.~n", [AAA]).
** 1: variable 'AAA' is unbound **
大文字だと文法違反のようだ。

# io:format("test ~w.~n", [aaa]).
test aaa.
ok
小文字ならOK。

# io:format("test ~w.~n", ["AAA"]).
test [65,65,65].
ok
""で囲むと文法違反にはならないが、文字列ではなく数字のリストに変換される。

6> io:format("test ~w.~n", ['AAA']).
test 'AAA'.
ok
''で囲むと望みどおりのAAAが表示される。

# io:format("test 1:~w 2:~w ~~.~n", ['AAA','BBB']).
test 1:'AAA' 2:'BBB' ~.
ok
2つ以上表示させたい場合は、リストの要素を増やせば良い。
フォーマット部分の文字列には~wを2個書く。このへんはC++のboost:formatのようだ。
~を表示させたいときは~~と書けば良い。

次に最小値を求める関数を作成する。
ここでは「guard」というのを使用する。

<tut6.erl>
-module(tut6).
-export([list_min/1]).
list_min([Head|Rest])->list_min(Rest, Head).
list_min([], Result)->Result;
list_min([Head|Rest], Result) when Head < Result ->list_min(Rest, Head);
list_min([Head|Rest], Result)->list_min(Rest, Result).

実行すると、
# c(tut6).
./tut6.erl:6: Warning: variable 'Head' is unused
{ok,tut6}
# tut6:list_min([7,2,5,7,9,1,3]).
1
のようになり、最小値が得られる。「when」というのが関数実行の条件で、
trueの場合に関数の中身が実行される。そうでない場合は、関数の次の定義が実行される。
このように条件をテストすることを「guard」と呼ぶようだ。

guardで使える条件文は <, >, == <=, >=, /=がある。
/=はnot equalであり、C++とは違うので注意。

リストにはもう少し機能がある。| operatorにはリストの先頭に要素を追加する機能がある。
まず、リストを作成する。
# L = ['AAA','BBB'].
['AAA','BBB']

| operatorでリストの先頭に要素を追加する。
# L3 = ['CCC'|L].
['CCC','AAA','BBB']

逆向きに書くと、
# L2 = [L|'CCC'].
[['AAA','BBB']|'CCC']
となり、'CCC'のみ持つリストの先頭に['AAA','BBB']というリストが
追加されることになる。

これを使って、リストの順序を逆にする関数を作ってみる。
<tut8.erl>
-module(tut8).
-export([reverse/1]).
reverse(List)->reverse(List, []).
reverse([Head|Rest], ReversedList)->reverse(Rest, [Head|ReversedList]);
reverse([], ReversedList)->ReversedList.

4行目でHeadから順にReversedListの先頭に追加しているところがミソ。
# c(tut8).   
{ok,tut8}
# tut8:reverse([1,2,3,4,5]).
[5,4,3,2,1]
逆順になった。

関数に連続した処理をさせたい場合は、「,」で区切ればよく、
<tut7a.erl>
-module(tut7a).
-export([format/1]).
format(Str)->
  io:format("test : ~w~n", [Str]),
  io:format("test2 : ~w~n", [Str]).

のように書ける。これを実行すると、
# c(tut7a).    
{ok,tut7a}
# tut7a:format(aa).
test : aa
test2 : aa
ok

となり、文字列の出力を2回行うようになる。
今度は与えられた値のリストから最小値と最大値をとってみる。
<tut7b.erl>
-module(tut7b).
-export([minmax/1]).

minmax([Head|Rest])->minmax(Rest, Head, Head).
minmax([Head|Rest], Min, Max)->
  if Head < Min -> NewMin = Head;
    true -> NewMin = Min
  end,
  if Head > Max -> NewMax = Head;
    true -> NewMax = Max
  end,
  minmax(Rest, NewMin, NewMax);
minmax([], Min, Max) -> {Min, Max}.

コンパイルして実行してみる。
# c(tut7b).
{ok,tut7b}
# tut7b:minmax([1,2,3,4,5,6,7]).
{1,7}
# tut7b:minmax([5,3,8,0,2,4,5]).
{0,8}

たしかに最小値と最大値がとれている。
条件文ifは上記のように書けばよく、条件の間は;で区切る。
endの直前の条件文には;はいらない。
elseがないので、代わりに一番最後にtrue->とすることで対応する。

もう少しifについて調べてみる。
<tut9.erl>
-module(tut9).
-export([test/2]).

test(X,Y)->
  if X==1 -> 'X == 1';
    Y==2 -> 'Y == 2';
    X==2, Y==5 -> 'X==2, Y==5';
    X==3;
    Y==4 -> 'X==3 or Y==4';
    (X==5) and (Y==5) -> 'X==5 and Y==5'
  end.

実行すると、
# c(tut9).
{ok,tut9}
# tut9:test(1,2).
'X == 1'
Xが1なので、一番最初の条件に一致する。

# tut9:test(0,2).
'Y == 2'
Xが1でなく、Yが2なので、2番目の条件に一致する。

# tut9:test(2,5).
'X==2, Y==5'
今度は3番目の条件に一致する。

# tut9:test(3,5).
'X==3 or Y==4'
これは4番目の条件に一致する。
C++でいうswitch-cast文と似ていて、;のみで->がない場合は、
->が見つかったところから実行するようだ。

# tut9:test(5,5).
'X==5 and Y==5'
最後は両方共が5の場合の条件である。

# tut9:test(6,5).

=ERROR REPORT==== 1-May-2007::17:01:33 ===
Error in process <0.44.0> with exit value: {if_clause,[{tut9,test,2},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {if_clause,[{tut9,test,2},{shell,exprs,6},{shell,eval_loop,3}]} **
条件にマッチしないとこんな風にエラーになる。

ちなみに10行目を
 (X==5) and (Y==5)
と書かず、
 X==5 and Y==5
と書くとコンパイルエラーになる。

最後に高階関数(higher order functions)について試してみる。
C++でいう関数ポインタみたいなもの。
シェルから使うと、次のようになる。

18> Fn = fun (X)->X*3 end.
#Fun<erl_eval.6.56006484>
19> Fn(5).
15

引数の値を3倍する関数Fnを定義して、その引数に5を入れると15が出力される。
高階関数の定義はfunとendで囲むようだ。

標準モジュールのlistsを使うと、次のようなことができる。
20> lists:map(Fn, [1,2,3]).
[3,6,9]

リスト[1,2,3]の各要素に対してFnを適用し、その結果をリストに入れる操作が行われている。

他にも、
25> Fp = fun (X)->io:format("elm : ~w~n",[X]) end.
#Fun<erl_eval.6.56006484>
26> lists:map(Fp, [1,2,3]).
elm : 1
elm : 2
elm : 3
[ok,ok,ok]
27> lists:foreach(Fp, [1,2,3]).
elm : 1
elm : 2
elm : 3
ok
といったことができる。

ソートも次のようにできる。
30> lists:sort([2,3,1]).
[1,2,3]
31> lists:sort(fun(X,Y)->X<Y end,[2,3,1]).
[1,2,3]
32> lists:sort(fun(X,Y)->X>Y end,[2,3,1]).
[3,2,1]

名前とペアになっている要素からなるリストに対してもソートできる。
33> lists:sort(fun({_,X},{_,Y})->X<Y end,[{'A',2},{'B',3},{'C',1}]).
[{'C',1},{'A',2},{'B',3}]

ここで、「 _ 」はanonymous variableと呼ばれ、使わない値に使用するようだ。
今の例では、文字は比較に使わないので「 _ 」を使って表現を簡略化した。

今回はここまで。