初期のErlangのモジュールには階層構造がありませんでしたが、
モジュールを機能ごとに分類するためにパッケージという概念が導入されました。
Erlangにおけるパッケージとは、「モジュールの階層構造」のことを表しています。Javaのパッケージは
アクセス手段等の複雑な役割を持っていますが、Erlangのパッケージは物理的な階層構造を中心とする概念のため
特に難しいものではありません。
パッケージはBIFのpackageが 管理しているものです。この節ではおもに利用方法だけを利用しますので、より詳細に調べたい方は マニュアルを参照下さい。
パッケージを利用する際に、今までと違った点が2つあります。
それは
という点のみです。特に新しい関数などは利用しません。
以下では簡単なサンプルを扱います。
モジュールの構成としては以下のようになっています。
package_test/main.erl
package_test/pack1/add_mod.erl
package_test/pack2/mul_mod.erl
-module(main).
-export([test/2,out/0]).
test(X,Y) ->
Add = pack1.add_mod:add(X,Y),
io:format("add ~p~n",[Add]),
Mul = pack2.mul_mod:mul(X,Y),
io:format("mul ~p~n",[Mul]).
out() ->
io:format("in main~n",[]).
-module(pack1.add_mod).
-export([add/2,use_upper_modfunc/0]).
add(X,Y) ->
X + Y.
use_upper_modfunc() ->
.main:out().
-module(pack2.mul_mod).
-export([mul/2]).
mul(X,Y) ->
X * Y.
注目するべき点は、モジュールの宣言とモジュールの呼び出し部分でした。
階層構造が符号 . で繋がれているのがわかります。
特に難しい点はないと思うのですが、一つだけ注意したほうがいい点があります。
それは、「パッケージ名(ディレクトリ名)もアトムである」という点です。
したがって、パッケージ名はアトムと同様に小文字英語から始めることが推奨されます。
スペースの利用や、日本語の利用はエラーの元になるので避けることが望ましいです。
実行結果は以下の通りになります。
普通の関数と同じように動いているのがわかります。
> main:test(3,5).
add 8
mul 15
ok
ある程度パッケージという概念について理解できたと思うので、もう少し詳細に見ていきます。
まずは実験からスタートしてみます。add_modを直接呼び出してみます。
> pwd().
/Users/yuichi/erlang/package_test/pack1
ok
> add_mod:add(3,4).
=ERROR REPORT==== 7-Jun-2008::13:15:41 ===
Loading of /Users/yuichi/erlang/package_test/pack1/add_mod.beam failed: badfile
** exception error: undefined function add_mod:add/2
=ERROR REPORT==== 7-Jun-2008::13:15:42 ===
beam/beam_load.c(1035): Error loading module add_mod:
module name in object code is pack1.add_mod
> pack1.add_mod:add(3,4).
7
add_modというモジュール名で呼び出すとエラーが出ています。pack1.add_modというモジュール名で呼び出すと大丈夫なようです。
モジュール名はモジュール名宣言されたものと同じ名前で利用しないと駄目なようです。
次に上の階層にあるモジュールを利用してみます。
> pwd().
/Users/yuichi/erlang/package_test/pack1
ok
13> pack1.add_mod:use_upper_modfunc().
in main
ok
use_upper_modfunc/0の中を見てみると、mainの関数の呼び出しが
.main:out().
のようになっています。一番最初に . がついています。これはパッケージの階層の一番上を意味しています。
パッケージは一番上の階層を起点として、絶対表記を行ないます。
今回のプログラムのルートパッケージは package_test です。
また、関数の呼び出しの際に、モジュールが属するパッケージ名を省略した場合は 自分と同じ階層にあるモジュールだという扱いになります。
BIFはルートパッケージにあるという扱いになっていますので、利用する際は
.lists:reverse(List).
といった呼び出し方を行ないます。
モジュールのインポートも可能です。インポートの際に、 ルートパッケージからの階層を記したモジュールを指定するのみです。
-import(fee.fie.foe.m2).
fee fie foe がパッケージ名で m2 がモジュール名となっています。
インポートを行なうことで、本来なら
fee.fie.foe.m2:h(X)
と呼び出さないといけないものを、
m2:h(X)
と呼び出すことが可能となります。