2007年4月30日月曜日

erlang その1

erlangという関数型言語のプログラミング言語を使ってみる。
getting started を見ながらやってみることにする。
http://www.erlang.org/

起動するにはコマンドラインから
# erl
と入力する。

何か計算をさせてみる。
# 1 + 2.
3
と表示される。最後のピリオドはC++でいう;に相当するようだ。

括弧で優先順位をきめられる。
# (1+2)*5.
15

erlシェルを終了したいときはCtrl+Cを押すと
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
と表示されるので、aを押すと終了する。

今度はファイルにソースを書いて、コンパイルしてから使ってみる。
[tut.erl]ファイルの中身に次のように書く。

-module(tut).
-export([double/1]).
double(X) -> 2*X.

そして、
# c(tut).
{ok,tut}
でコンパイル完了。
使うには、
# tut:double(50).
100
とすると、結果に2倍された値が表示される。
ところで、

-module(tut).
-export([double/1]).
double(x) -> 2*x.

つまり、Xをxに書き換えるとコンパイルが通らない。
チュートリアルの後の方に書いてあるが、
変数の先頭の文字が大文字か小文字かによって意味が変わるようだ。

今度は再帰。ループが使えないのでその代わりに使うようだ。
ためしに、1からXまでの値を足すプログラムを書いてみる。

-module(tut1).
-export([sum/1]).
sum(1)->1;
sum(X)->X+sum(X-1).

重要なのは、3行目のsumの定義の最後を;にすること。
もし.を使うとsumの定義が終了して、4行目で再定義されてしまうことになり、
コンパイルエラーになる。

さて、実行してみると、
# tut1:sum(10).
55
で、あってる。

今度は、このファイルに関数powを追加してみる。

-module(tut1).
-export([sum/1, pow/2]).
sum(1)->1;
sum(X)->X+sum(X-1).
pow(X,1)->X;
pow(X,Y)->X*pow(X,Y-1).

コンパイルして実行してみる。
# tut1:pow(2,8).
256

おそらく意外とC++とかでは面倒なことになりそうな2^1024を計算してみる。
# tut1:pow(2,1024).
17976931348623159077293051907890247336179769789423065727343008115773267580
55009631327084773224075360211201138798713933576587897688144166224928474306
39474124377767893424865485276302219601246094119453082952085005768838150682
34246288147391311054082723716335051068458629823994724593847971630483535632
9624224137216

合ってるのかどうかわからんが、たぶん正しいのだろう。
多倍長整数があるのはこういうときは便利だ。

今度はAtomsとかいうデータ型を使ってみる。
tut2.erlファイルを作って、次のような内容を記録する。
単位系を光年←→パーセクへ変換する関数である。

-module(tut2).
-export([convert/2]).
convert(L, parsec)->L/3.26;
convert(P, lightyear)->P*3.26.

# c(tut2).
{ok,tut2}
# tut2:convert(3, parsec).
0.920245
# tut2:convert(3, lightyear).
9.78000

第2引数の値によって、関数の呼ばれる部分が変わるということのようだ。
で、その第2引数が数字ではなくて、atomだということだろう。

次はTuplesだ。
値をひとまとめにして扱おうということだ。C++でいう構造体に似ているかな。
ここでは数字を単位と一つにまとめて処理してみる。
<tut3.erl>
-module(tut3).
-export([convert_length/1]).
convert_length({L, lightyear})->{L/3.26,parsec};
convert_length({P, parsec})->{P*3.26,lightyear}.

で、実行。
# c(tut3).
{ok,tut3}
# tut3:convert_length({3,parsec}).
{9.78000,lightyear}

計算できてる。無論、tupleの要素の位置を逆にしても同じことができる。
<tut3b.erl>
-module(tut3b).
-export([convert_length/1]).
convert_length({lightyear, L})->{parsec, L/3.26};
convert_length({parsec, P})->{lightyear, P*3.26}.

実行すると、
# c(tut3b).
{ok,tut3b}
# tut3b:convert_length({parsec,3}).
{lightyear,9.78000}
となって、逆にしてもOK。

次はListsだ。listは[]で囲む。
tupleと違って、サイズを変えられる。C++でいうとstd::listかな。
例えば、
# [First | TheRest] = [1,2,3,4,5,6,7].
[1,2,3,4,5,6,7]
# First.
1
# TheRest.
[2,3,4,5,6,7]
な風になる。|はリストの最初の要素と後の要素をわける。
コンマを使うと、要素ごとに分けられる。
# [First, Second | TheRest] = [1,2,3,4,5,6,7].
[1,2,3,4,5,6,7]
# First.
1
# Second.
2
# TheRest.
[3,4,5,6,7]

ちなみ、この2つの例を連続していれると、文句を言われる。
つまり、最初に定義したFirstを次の定義のFirstで上書きしていると。
定義済みの変数の消し方がわからんので、ここではerlを再起動して例を試した。

次に、リストの長さを求める関数を定義する。
<tut4.erl>
-module(tut4).
-export([list_length/1]).
list_length([])->0;
list_length([First|Rest])->1+list_length(Rest).

使ってみる。
# c(tut4).
./tut4.erl:4: Warning: variable 'First' is unused
{ok,tut4}
# tut4:list_length([1,2,3,4,5]).
5
警告がでたが、問題なく動作するようだ。
要素にatomを使ってもOK.
# tut4:list_length([a,b,c,d,e,f]).
6

ついでに文字列はどうなるかみてみる。
# tut4:list_length(["a","b"]).
2
""が何を意味するのか読んでいるチュートリアルの現時点では不明だが、
なにかの値として見てはくれているようだ。

# ["a","b"].
["a","b"]
ただ、リストの内容が表示されるだけ。

# [97,98].
"ab"
なんと、文字コードとして解釈してくれるようだ。
でも["a","b"]のときは気をきかせて"ab"と表示してくれるわけではないようだ。

============================
今回はこの辺で終了。

0 件のコメント :