次へ 前へ 目次へ 佐々木将人の個人ページへ

対話環境とプログラムのコンパイル(Erlang編)

 Erlangについては,対話環境の意味合いが変わってきます。
 同じ関数型言語であっても,LispとErlangの最大の違いは,Lispは基本的にインタープリターの言語であるのに対し,Erlangはコンパイラの言語です。コンパイラというのは,プログラムを事前に機械語に変換しておき,実行ファイルを作って,それを実行するものです。とはいえ,現在では直接機械語に変換するのではなく,なんらかの中間言語に変換し,その中間言語をさらに機械語に変換するとか,仮想機械を作ってその仮想機械の機械語に変換する(Erlangはこのパターンです。BEAMという仮想機械のアセンブラ?に変換します。)いずれ,事前に変換しておくのがポイントです。
 Erlangの対話環境は,事前に変換された仮想機械の機械語を呼び出すための仕組です。そして,Erlangもまた関数型言語なので,関数が単位になるのですが,この関数を管理するための仕組がこの対話環境だということもできます。Erlangの対話環境は「シェル」と言い,関数を操作することもできます。この操作にはコンパイルされた関数を操作することに加え,対話環境に直接入力された関数もまた含まれます。
 Erlangを終わらせる時は基本的には「q().」を入力します。
(その他のシェルモードにおけるコマンドは「資料 Erlangのシェルモードでのコマンド群」のとおり)

 後で詳しく説明しますが,Erlangにおいては,変数に値を一旦設定してしまうと,もはや変更することができないという特徴があります。シェルモードの場合には,それでは都合が悪いので,「f(変数名).」で当該変数名に設定された値を解除し,「f().」ですべての変数について設定された値を解除します。

 探し方が悪いのかもしれませんが,シェルの環境をそのまままるごと保存して,あとで再現する……というような芸当は,Erlangには用意されていないようです。
 Erlangではシェルモードでも相当なことができ,状況によっては数年単位でシェルが動き続ける……というようなこともあり得るようなのですが……。
 いずれ「対話環境で関数を定義すればその後はその関数が使用できる」のとは異なり,コンパイラを通すためには,プログラムファイルの中で関数だけ定義すればよいのではなく,いくつかの約束事を守らなければなりません。(ちなみにコンパイラに通す前のプログラムを記述したファイルを特に「ソース」と呼んでいます。)

 Erlangのソースは,基本的には次の構造をもっています。

1行目 moduleの宣言 例 -module(neko).
2行目 exportの宣言 例 -export([nibai/1]).
3行目以下 関数定義 例 nibai(X) -> X * 2.

1行目 moduleの宣言

 ソースの1行目は絶対にこのmoduleの宣言でなくてはいけません。
 形式としてはまず「-」引き続いて「module」という文字列,さらに()内に任意の文字列(モジュール名)となります。
 この文字列は,他のファイル,ひいては他の関数からは,「モジュール名:関数名(引数)」として利用することが「可能」になります。
 上の例で言うと,「neko:nibai(X)」になります。
(もっとも実際に利用するためにはmodule宣言だけではだめで2行目のexportの宣言が必要となります。)
 また,モジュール名はファイル名と同じでなければなりません。たとえば上のソースファイルであれば「neko.erl」でなければ,コンパイルできないことになります。
 最後に「.」ピリオドを忘れないように。(Lispやっているとよく忘れます。(自戒))

2行目 exportの宣言

 moduleの宣言の次にexportの宣言が来ます。これはなくてもコンパイル可能なのですが,exportがないと,このファイルで定義された関数を利用することができなくなってしまいます。したがって外から使う必要がある場合にはexportで宣言しておく必要があります。一方,他のファイルからは使われたくないという場合には,exportに含めないことで隠すことができます。
 形式としてはまず「-」引き続いて「export」という文字列,さらに()内に[]で囲まれた「関数名/引数の数」が必要な分だけ(複数あれば「,」で区切る)ということになります。Erlangでは関数名が同じでも引数の数が違うと別の関数扱いになります。例えば,同じnekoという関数名でも,neko(X)とneko(X,Y),neko(X,Y,Z)さらには引数のないneko()は,別の関数扱いになり,別の定義をしても全然かまわないということになります。そこでexportの際も,関数名だけではなく引数の数まであわせて指定する必要が出てきます。ちなみに引数の数を「アリティ」と言っています。

3行目以下 関数定義

 最後に関数を定義します。
 関数の定義は,「関数名(引数) -> 関数の定義」という形で行います。詳しい説明は後にしますが,「nibai(X) -> X * 2.」が,「アリティが1である=引数を1個とる関数nibaiは,引数×2として定義されている」の意味だというのは,なんとなく想像がつくのではないかと思います。
 関数の定義が1つのファイルの中に複数あっても一向に差支えありません。

コンパイル

 コンパイルすることで,モジュール名.beamというファイルができます。シェルを動かして,動かしたい関数を指定すると動くという仕掛けです。

ターミナルもしくはコマンドプロンプトから

> erlc ソースファイル名.erl
ということは
> erlc モジュール名.erl ということでもあるのですが

シェルから

1> c(モジュール名).
もしくは
2> compile:file(ファイル名).

モジュール内でコンパイルする場合

compile:file(ファイル名).

(2023.5.17. 初版)
(2023.6.9. 改訂)

次へ 前へ 目次へ 佐々木将人の個人ページへ