前田耕
平
![]() |
Erlang というプログラミング言語があります。 今回、 これを勉強してみようと思ったのは、 Erlang そのも のがきっかけではなく、 いつものように別のものがきっかけです。 今回は、 CouchDB という Apache Incubator*3 に あった*4 、 ドキュメント指向のデータベースを友人から教えてもらったのがきっかけでした。 CouchDB が Erlang と JavaScript で実装 されている、 というので、 「Erlangって何だろう?」 と興味を持ちました。
CouchDB の特徴には以下のものがあります。
RDB のように事前にしっかりとスキーマの定義を行っておく必要はなく、 HTTP PUT でデータ(=ドキュメント) を作 成・更新し、 GET でデータを取得し、 DELETE でデータを削除する、 ちょっと変わったデータベースです。 RDB を置き換え るものではないので、 摘要範囲は正直まだよく分かりません。 ですが、 面白そうなので友人とこれを広めるべく、 目下水面下で 活動中です。
CouchDB のアーキテクチャについては、 CouchDB Project のホームページから転載した、 下記のシステム概念図をご覧下 さい。 これらの実装は主に Erlang によるものです。
また、 CouchDB については、 水面下の活動の一環で翻訳なども行っているので、 また別の機会にお話できればと思い ます。
本題の Erlang ですが、 CouchDB に興味を持ち、 さらにその中身をどうなっているのを知りたいと思ったのですが、 Erlang と いう言語を知りません。 関数型プログラミングで、 並列処理、 分散処理、 耐障害性を兼ね備えた、 並行指向プログラミングとい うのですが、 そもそも文法がまったく分からないので、 ソースコードだけを眺めて理解できるものではないな、 ということから 勉強を始めてみました。 また、 並列処理、 分散処理に興味を持っていたので、 興味がうまい具合に重なったのも、 きっかけとな りました。
Erlang の歴史
Erlang は、 Ericsson Computer Science Laboratory で、 分散化された環境、 耐障害、 ある程度のリアルタイム性、 無停止で
稼働する、 といった条件のシステムを構築できるように設計されたプログラミング言語です。 もともとは、 エリクソンの社内だ
けで使われていましたが、 1998 年にオープンソースとして公開されました。 ライセンスは、 Erlang Public
License*5 で、
Mozilla Public License の派生ライセンスです。 関数型で並列指向のプログラミング言語ということですが、 20
年を超える歴史と、 高度な信頼性が要求される通信機器の分野でも実績があり、 例えばエリクソンの
AXD301*6 な
どがあるそうです。
仕様
プログラミング Erlang という書籍を一通り読んで、 今 2 周目で実際に手を動かしている段階ですが、 その中で興味を持った特
徴を挙げます。
自分には馴染みが薄いものばかりです。 特に、 「変数の書き換えはできない」 なんて、 定数じゃないの?と思いました。 詳しくは 後述。
Erlang による最近の実装例
Erlang で実装されているソフトウェアの例です。 これらは deb パッケージになっており、 Lenny にも含まれてい
ます。
Erlang の検証事例
数年前から、 一部では流行りらしいので、 検証事例もちらほら出ています。
一般的に普及していくのはまだこれからみたいな感じしますが、 あまり使われていないうちに遊んでおこうと思い ます。
Debian では数はまだ少ないものの Erlang と Erlang で書かれたソフトウェアのパッケージがあります。
$ apt-cache search erlang | wc -l
63 |
ちなみに、 例として挙げた CouchDB や YAWS も deb パッケージになっています。
Erlang を使うために最低限必要なパッケージは次の erlang-base パッケージです。 対話型ではなく、 ソース コードを書くのには emacs の Erlang 用のモードもあるので、 それも一緒にインストールしておくと良いで しょう。
$ sudo apt-get install erlang-base erlang-mode
|
ところで、 erlang-base パッケージではなく、 erlang パッケージをインストールすれば、 erlang ソースパッケージから分割さ れている関連パッケージも軒並みインストールされるので便利かもしれませんが、 この場合は依存関係も含めて関連するパッ ケージが 90 以上導入されます。 状況に応じて適宜選択してください。
$ sudo apt-get install erlang
|
対話型で Erlang を使うには、 erl コマンドを実行します。 すると、 Erlang shell(Eshell) が起動します。
$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:2] [async-threads:0] [kernel-poll:false] Eshell V5.6.5 (abort with ^G) 1> |
“1>” はプロンプトです。 Eshell を終了するには、 q(). と入力するか、
1> q().
ok 2> $ |
または、 ctrl+ c, a と入力します。
1>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution a $ |
では、 変数を書き換えれない、 という件の特徴をみてみます。
1> A=10.
10 2> A=20. ** exception error: no match of right hand side value 20 |
見ての通り、 エラーになってしまいました。 Erlang の変数の書き換えはできない、 単一代入変数なのです。 もう一度代入の 仕方を変えて見てみましょう。
1> A1=1.
1 2> A2=2. 2 3> A3=A1+A2. 3 4> A3=3. 3 5> A3=A1+2. 3 6> A3=A1+4. ** exception error: no match of right hand side value 5 7> A1=A2+A3. ** exception error: no match of right hand side value 5 8> A1=A3-A2. 1 |
1,2,3 のように未代入の変数に対しては値を再代入できますが、 6,7 のように一度代入された変数に対しては違う値を代入し なおすことができないことが分かります。 しかし、 4,5,8 のように同じ値であれば再代入できるように見えます。 実は、 4,5,8 は変数を再代入しているわけではなく、 代入済みの変数に対し、 パターン照合を行っているの です。
代入済みの変数のことを束縛済み変数、 と言いますが、 未束縛状態の変数に対しては、 イコールは値の代入を行いますが、 束 縛済みの変数に対してはパターン照合を行う、 という訳です。
今までこんな仕様のプログラミング言語は見たことなかったのですが、 プログラミング言語ではなく、 実は数学の代数であれ ば同じような考え方ができることが分かります。 例えば、 x + y = 6,x-y = 2 という関数を考えてみます。 この状態では、 x, y の代数は x=4, y=2 以外の値にはなりません。 単一代入変数は、 数学の代数と同じようなものと考えれば、 良いのかもしれま せん。
次に、 ソースコードからコンパイルして実行する方法について説明します。 プログラムを実行する方法は、 次の 3 種類があり ます。
例としてはやはり、 Hello World を書いてみます。 これは引数なしのプログラムです。 引数ありとなしで はプログラム実行時に若干の違いが出てきます。 hello.erl というファイル名で次のプログラムを用意して下 さい。
-module(hello).
-export([start/0]). start() -> io:format("Hello world on Erlang~n"). |
Erlang のプログラムはモジュールを基本単位とし、 どの関数もモジュールに属する構造になっています。 コードを 実行するには、 まずモジュールをコンパイルしなければなりません。 コンパイルしたモジュールは、 拡張子 beam*9 とい う名前のファイルが生成されます。 コンパイルには2つのやり方があります。
先ほどの hello.erl を Eshell からコンパイルし、 実行するには、 次の手順です。
1> c(hello).
{ok,hello} 2> he heart hello 2> hello:start(). Hello world on Erlang ok 3> |
c(hello). でコンパイルの実行を行います。 c() の引数が module(hello) および、 プログラムファイル名 hello.erl と一致するこ とに注意してください。 コンパイルすると、 hello.beam ファイルが生成されます。 これは Erlang VM 向けのバイナリコード です。
$ ls -lrt hello.*
-rwx------ 1 user user 90 2009-05-14 01:35 hello.erl -rw------- 1 user user 552 2009-05-14 01:35 hello.beam $ file hello.beam hello.beam: Erlang BEAM file |
シェルからコンパイルする場合は、 erlc コマンドを使います。
$ erlc hello.erl
$ ls -lrt hello.* -rwx------ 1 user user 90 2009-05-14 01:35 hello.erl -rw------- 1 user user 708 2009-05-14 01:53 hello.beam |
実行もシェルから行ってみます。
$ erl -noshell -s hello start -s init stop
Hello world on Erlang |
無事、 実行できました。 なお、 各引数は次の意味があります。
Erlang では escript という仕組みもあり、 これを使うとプログラムをコンパイルせずにスクリプトとして直接実行でき ます。
関数 hello:start を escript として実行するには、 次のようにファイルを書き換えます。 ファイル名は今回、 hello.esc としまし たが、 コンパイルするときと違い、 任意の拡張子で問題ありません。
#!/usr/bin/env escript
main(_) -> io:format("Hello world on Erlang~n"). |
これを実行権限をつけて実行してみます。
$ chmod 700 hello.esc
$ ./hello.esc Hello world on Erlang |
今回の例は、 引数なしでしたが、 シェルで実行する場合のプログラムはどうやって引数を渡せば良いのでしょうか。 今度は引数 ありのプログラムを試してみます。
フィボナッチ数列を計算する関数を書いてみました。 まず、 Eshell で引数を渡す場合です。
-module(fib).
-export([fib/1]). fib(0) -> 1; fib(1) -> 1; fib(N) -> fib(N-2) + fib(N-1). |
実行するとこんな感じ。
1> c(fib)
1> . {ok,fib} 2> fib:fib(10). 89 3> fib:fib(20). 10946 4> fib:fib(30). 1346269 |
シェルから実行する場合は、 書き方を変える必要があります。
-module(fib1).
-export([main/1]). main([A]) -> I = list_to_integer(atom_to_list(A)), F = fib(I), io:format("fibonacci ~w = ~w~n", [I, F]), init:stop(). fib(0) -> 1; fib(1) -> 1; fib(N) -> fib(N-2) + fib(N-1). |
これをシェルでコンパイル、 実行してみます。
$ erlc fib1.erl
$ erl -noshell -s fib1 main 10 -s init stop fibonacci 10 = 89 $ erl -noshell -s fib1 main 20 -s init stop fibonacci 20 = 10946 $ erl -noshell -s fib1 main 30 -s init stop fibonacci 30 = 1346269 |
前述のとおり、 Erlang は beam ファイルからコードをロードするか、 escript で実行する必要があります。 Erlang のランタイ ムシステムは、 コード自動ロード機構を利用しています。 現在のロードパスは Eshell から code:get_path() 確認することがで きます。
1> code:get_path().
[".","/usr/lib/erlang/lib/kernel-2.12.5/ebin", "/usr/lib/erlang/lib/stdlib-1.15.5/ebin", "/usr/lib/erlang/lib/xmerl-1.1.10/ebin", "/usr/lib/erlang/lib/webtool-0.8.3.2/ebin", "/usr/lib/erlang/lib/typer-0.1.5/ebin", "/usr/lib/erlang/lib/tv-2.1.4.2/ebin", "/usr/lib/erlang/lib/tools-2.6.2/ebin", "/usr/lib/erlang/lib/toolbar-1.3.0.1/ebin", "/usr/lib/erlang/lib/test_server-3.2.4/ebin", "/usr/lib/erlang/lib/syntax_tools-1.5.6/ebin", "/usr/lib/erlang/lib/ssl-3.10/ebin", "/usr/lib/erlang/lib/ssh-1.0.2/ebin", "/usr/lib/erlang/lib/snmp-4.12/ebin", "/usr/lib/erlang/lib/sasl-2.1.5.4/ebin", "/usr/lib/erlang/lib/runtime_tools-1.7.3/ebin", "/usr/lib/erlang/lib/public_key-0.1/ebin", "/usr/lib/erlang/lib/pman-2.6/ebin", "/usr/lib/erlang/lib/percept-0.7.3/ebin", "/usr/lib/erlang/lib/parsetools-1.4.5/ebin", "/usr/lib/erlang/lib/otp_mibs-1.0.4.1/ebin", "/usr/lib/erlang/lib/os_mon-2.1.8/ebin", "/usr/lib/erlang/lib/orber-3.6.10/ebin", "/usr/lib/erlang/lib/odbc-2.10.3/ebin", "/usr/lib/erlang/lib/observer-0.9.7.4/ebin", "/usr/lib/erlang/lib/mnesia-4.4.7/ebin", "/usr/lib/erlang/lib/megaco-3.9.1.1/ebin", "/usr/lib/erlang/lib/inviso-0.6/ebin", [...]|...] |
先頭に、 “.” が入っているため、 カレントディレクトリにある、 beam ファイルは自動的にコードがロードされるため、 実行 できたわけです。 コードパスは/usr/lib/erlang/lib が共通しています。 これは、 Erlang のデフォルトのライブラリディレクト リで、 code:lib_dir() で確認できます。
1> code:lib_dir().
"/usr/lib/erlang/lib" |
先ほど作成した hello モジュールもこのライブラリディレクトリ配下に配置します。 しかし、 ここに配置すると自動的にロー ドパスに入るわけではないので、 実際に必要な場合は、 ちゃんと指定する必要があります。
さて、 hello-erlang-1.0 というディレクトリを作り、 hello モジュール関係は全てこのディレクトリに移します。
$ mkdir hello-erlang-1.0
$ mv hello.erl hello.esc |
Makefile を用意します。
.SUFFIXES: .erl .beam .yrl
.erl.beam: erlc -W $< BINDIR?=/usr/lib/erlang/lib/hello-1.0/ebin ERL = erl -boot start_clean # compile erlang module list MODS = hello all: compile ${ERL} -noshell -s hello start -s init stop compile: ${MODS:%=%.beam} install: install -d ${DESTDIR}${BINDIR} install -m 644 hello.beam ${DESTDIR}${BINDIR} install -m 755 hello.esc ${DESTDIR}$/usr/bin/ clean: rm -rf *.beam erl_crash.dump |
dh_make を実行します。 今回は CDBS 形式にしてみます。
$ dh_make -c gpl -b --createorig
Maintainer name : Kouhei Maeda Email-Address : mkouhei@palmtb.net Date : Fri, 15 May 2009 00:36:24 +0900 Package Name : hello-erlang Version : 1.0 License : gpl3 Using dpatch : no Using quilt : no Type of Package : cdbs Hit <enter> to confirm: Skipping creating ../hello-erlang_1.0.orig.tar.gz because it already exists Done. Please edit the files in the debian/ subdirectory now. You should also check that the hello-erlang Makefiles install into $DESTDIR and not in / . |
debian ディレクトリ以下を編集します。 まず、 不要なサンプルファイルを削除します。
$ cd debian
$ rm *.ex *.EX |
changelog を編集します。
$ dch
hello-erlang (1.0-1) unstable; urgency=low * Initial releas -- Kouhei Maeda <mkouhei@palmtb.net> Thu, 14 May 2009 22:56:51 +0900 |
control を編集します。 erlang-base パッケージが必要なので追記します。
Source: hello-erlang
Section: game Priority: extra Maintainer: Kouhei Maeda <mkouhei@palmtb.net> Build-Depends: cdbs, debhelper (>= 7), erlang-dev Standards-Version: 3.8.1 Homepage: http://www.palmtb.net/ Package: hello-erlang Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ${erlang-base:Depends} Description: Hello World for Erlang. Hello World Erlang version. |
copyright を編集します。
This package was debianized by:
Kouhei Maeda <mkouhei@palmtb.net> on Thu, 14 May 2009 22:54:34 +0900 Upstream Author(s): Kouhei Maeda <mkouhei@palmtb.net> Copyright: <Copyright (C) 2009 Kouhei Maeda> License: (以下略) |
rules を編集します。 dh_make で生成された時は、 include 文しかないので、 他を追加します。 特に、 DEB_FIXPERMS_EXCLUDE で、 hello.beam を指定しておかないと、 インストール時に実行権限が付与されてしまいます。 *11beam ファイルは Erlang VM が読み込むだけですので、 実行権は必要ありません。
#!/usr/bin/make -f
DEB_MAKE_CHECK_TARGET := DEB_FIXPERMS_EXCLUDE := hello.beam include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/makefile.mk binary-arch binary-indep: build DEB_MAKE_INSTALL_TARGET := install DESTDIR=$(DEB_DESTDIR)$(cdbs_curpkg) # Add here any variable or target overrides you need. |
以上が終わったら、 debuild を実行します。
$ debuild -us -uc
\end{commadline} pbuilder を実行します。 \begin{commandline} $ sudo pbuilder create --distribution sid $ sudo pbuilder build hello-erlang_1.0-1.dsc |
問題なければ、 最後にインストール、 アンインストールできるか確認しておきます。
$ sudo dpkg -i hello-erlang_1.0-1_amd64.deb
未選択パッケージ hello-erlang を選択しています。 (データベースを読み込んでいます ... 現在 193995 個のファイルとディレクトリがインストールされています。 ) (hello-erlang_1.0-1_amd64.deb から) hello-erlang を展開しています... hello-erlang (1.0-1) を設定しています ... $ dpkg -L hello-erlang /. /usr /usr/bin /usr/bin/hello.esc /usr/share /usr/share/doc /usr/share/doc/hello-erlang /usr/share/doc/hello-erlang/changelog.Debian.gz /usr/share/doc/hello-erlang/README.Debian /usr/share/doc/hello-erlang/copyright /usr/sbin /usr/lib /usr/lib/erlang /usr/lib/erlang/lib /usr/lib/erlang/lib/hello-1.0 /usr/lib/erlang/lib/hello-1.0/ebin /usr/lib/erlang/lib/hello-1.0/ebin/hello.beam $ hello.esc Hello world on Erlang $ erl -noshell -pa /usr/lib/erlang/lib/hello-1.0/ebin -s hello start -s init stop Hello world on Erlang $ sudo apt-get remove --purge hello-erlang パッケージリストを読み込んでいます... 完了 依 存 関 係 ツ リ ー を 作 成 し て い ま す 状態情報を読み取っています... 完了 以 下 の パ ッケ ー ジ が 自 動 で イ ン ス ト ー ルされましたが、 もう必要とされていません : (snip) これらを削除するには ’apt-get autoremove’ を利用してください。 以 下 の パ ッケ ー ジ は 「削 除 」 さ れ ま す : hello-erlang* アップグレード: 0 個、 新規インストール: 0 個、 削除: 1 個、 保留: 17 個。 こ の 操 作 後 に 73.7kB のディスク容量が解放されます。 続 行 し ま す か [Y/n]? (データベースを読み込んでいます ... 現在 194002 個のファイルとディレクトリがインストールされています。 ) hello-erlang を削除しています ... |
今回、 Erlang の入り口を少しだけ眺めてみました。 まだまだ分からないことが多いのでさらに勉強していきます。 また、 最後 に記述したパッケージの作成については、 Erlang のコードパスは自動的にロードされないので、 パッケージにす る=パッケージにされたコードが便利に使える訳ではありません。 先月の勉強会で紹介された OCaml では、 dh-ocaml というパッケージ作成支援ツールがありますが、 Erlang にはありませんでした。 Erlang 独自に必要な 設定を支援する、 dh-erlang のようなツールがあると、 Debian でも Erlang はさらに便利になるなと思いま した。
第 52 回東京エリア Debian 勉強会 2009 年 5 月
____________________________________________________________________________________________