Erlang-quick-guide
アーラン-概要
Erlangは関数型プログラミング言語であり、ランタイム環境も備えています。 並行性、配布、およびフォールトトレランスを統合的にサポートするように構築されました。 Erlangは元々、エリクソンのいくつかの大型通信システムで使用するために開発されました。
Erlangの最初のバージョンは、1986年にJoe Armstrong、Robert Virding、およびMike Williamsによって開発されました。 元々はエリクソン内の独自言語でした。 その後、1998年にオープンソース言語としてリリースされました。 Erlangは、ErlangのミドルウェアとライブラリのコレクションであるOTPとともに、エリクソンのOTP製品ユニットによってサポートおよび保守され、広く Erlang/OTP と呼ばれています。
なぜアーラン?
次の要件がある場合は、Erlangを使用してアプリケーションを開発する必要があります-
- アプリケーションは、多数の同時アクティビティを処理する必要があります。
- コンピューターのネットワーク上で簡単に配布できる必要があります。
- ソフトウェアとハードウェアの両方のエラーに対してアプリケーションをフォールトトレラントにする機能が必要です。
- アプリケーションはスケーラブルでなければなりません。 これは、ほとんどまたはまったく変更せずに、複数のサーバーにまたがる機能を持つ必要があることを意味します。
- アプリケーション自体を停止して再起動することなく、簡単にアップグレードおよび再構成できる必要があります。
- アプリケーションは、特定の厳密な時間枠内でユーザーに応答する必要があります。
Erlangの公式Webサイトはhttps://www.erlang.org/です。
アーラン-環境
Erlangでの作業を開始する前に、システムで実行されているErlangの完全に機能するバージョンがあることを確認する必要があります。 このセクションでは、Erlangのインストールと、Erlangを開始するためのWindowsマシンでのその後の構成について説明します。
インストールを進める前に、次のシステム要件が満たされていることを確認してください。
システム要求
Memory | 2 GB RAM (recommended) |
Disk Space | No minimum requirement. Preferably to have enough storage to store the applications which will be created using Erlang. |
Operating System Version | Erlang can be installed on Windows, Ubuntu/Debian, Mac OS X. |
Erlangのダウンロード
Erlangをダウンロードするには、次のURLにアクセスする必要があります-https://www.erlang.org/downloads[www.erlang.org/downloads]。
このページにはさまざまなダウンロードがあり、LinuxおよびMacプラットフォームで言語をダウンロードしてインストールするために必要な手順もあります。
[OTP 18.3 Windows 32ビットバイナリファイル]をクリックして、Erlang Windowsインストールファイルのダウンロードを開始します。
Erlangインストール
次の手順では、WindowsにErlangをインストールする方法について詳しく説明します-
- ステップ1 *-前のセクションでダウンロードしたインストーラーを起動します。 インストーラーが起動したら、[実行]をクリックします。
- ステップ2 *-次の画面で[次へ]をクリックして、インストールされるデフォルトコンポーネントを受け入れます。
- ステップ3 *-デフォルトのインストールパスを受け入れて、[次へ]をクリックします。
- ステップ4 *-作成されるデフォルトのスタートメニュー項目を受け入れ、[次へ]をクリックします。
- ステップ5 *-インストールが完了したら、[閉じる]をクリックしてインストールを完了します。
アーラン構成
インストールが完了したら、次の設定を実行して、Erlangがシステムで動作することを確認する必要があります。
OS | Output |
---|---|
Windows | Append the String; C:\Program Files(x86)\erl7.2.1\bin OR C:\Program Files\erl7.2.1\bin to the end of the system variable PATH. |
ここでコマンドプロンプトを開いて erl と入力すると、erlコマンドプロンプトが表示されるはずです。
おめでとうございます。これで、ラップトップでerlが正常に構成されました。
人気のあるIDEにプラグインをインストールする
プログラミング言語としてのErlangは、 EclipseやIntelliJ などの一般的なIDEでも利用できます。 これらのIDEで必要なプラグインを取得する方法を見てみましょう。これにより、Erlangを使用する際の選択肢が増えます。
Eclipseでのインストール
- ステップ1 *-Eclipseを開き、メニュー項目、[ヘルプ]→[新しいソフトウェアのインストール]をクリックします。
- ステップ2 *-https://download.erlide.org/update/[https://download.erlide.org/update]としてWork withリンクを入力します
次に追加をクリックします。
ステップ3 *-次に、プラグインの名前を入力するよう求められます。名前を *Erlide として入力します。 Okをクリックしてください。
- ステップ4 *-Eclipseは提供されたリンクをスキャンし、必要なプラグインを取得します。 プラグインを確認して、「次へ」をクリックします。
- ステップ5 *-次のダイアログボックスで、Eclipseはインストールされるすべてのコンポーネントを表示します。 Nextをクリックしてください。
- ステップ6 *-次のダイアログボックスで、Eclipseはインストールされているコンポーネントの確認を求めます。 Nextをクリックしてください。
- ステップ7 *-次のダイアログボックスで、ライセンス契約に同意する必要があります。 最後に、[完了]ボタンをクリックします。
その後、インストールが開始され、完了するとEclipseを再起動するように求められます。
Eclipseを再起動すると、プロジェクトを作成するときに、オプションとしてErlangを見ることができます。
IntelliJでのインストール
次の手順に従って、IntelliJをコンピューターにインストールしてください。
- ステップ1 *-IntelliJを開き、[設定]→[プラグイン]をクリックします。
- ステップ2 *-検索ボックスに「Erlang」と入力します。 画面の右側にErlangプラグインが表示されます。 [インストール]ボタンをクリックします。
- ステップ3 *-Erlangプラグインをインストールした後、IDEを再起動するように求められます。
IDEを再起動して新しいプロジェクトを作成しようとすると、Erlangプロジェクトを作成するオプションが表示されます。
Erlang-基本的な構文
Erlangの基本的な構文を理解するために、まず簡単な Hello World プログラムを見てみましょう。
例
% hello world program
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("Hello, world!\n").
上記のプログラムについては、次のことに注意する必要があります-
- %記号は、プログラムにコメントを追加するために使用されます。
- moduleステートメントは、プログラミング言語のように名前空間を追加するようなものです。 ここで、このコードは helloworld と呼ばれるモジュールの一部であることに言及しています。 エクスポート関数は、プログラム内で定義された関数を使用できるように使用されます。 startという関数を定義しており、start関数を使用するには、exportステートメントを使用する必要があります。/0 *は、関数「start」が0個のパラメーターを受け入れることを意味します。
- 最後に、開始関数を定義します。 ここでは、Erlangに必要なすべての入出力機能を備えた io という別のモジュールを使用します。 fwrite 関数を使用して、「Hello World」をコンソールに出力しました。
上記のプログラムの出力は次のようになります-
出力
Hello, world!
声明の一般的な形式
Erlangでは、Erlang言語で使用されるさまざまなシンボルがあることがわかりました。 単純なHello Worldプログラムから見たことを見てみましょう-
- ハイフン記号*(–)*は、通常、モジュール、インポート、およびエクスポートステートメントと共に使用されます。 ハイフン記号は、各ステートメントに意味を与えるために使用されます。 したがって、Hello worldプログラムの例は、次のプログラムに示されています-
-module(helloworld).
-export([start/0]).
各ステートメントは、ドット*(。)*記号で区切られます。 Erlangの各ステートメントは、この区切り文字で終わる必要があります。 Hello worldプログラムの例は、次のプログラムに示すとおりです-
io:fwrite("Hello, world!\n").
- スラッシュ*(/)*記号は、関数とともに使用され、関数によって受け入れられるパラメーターの数を定義します。
-export([start/0]).
モジュール
Erlangでは、すべてのコードはモジュールに分割されます。 モジュールは、一連の属性と関数宣言で構成されます。 これは、コードの異なるユニットを論理的に分離するために使用される他のプログラミング言語の名前空間の概念に似ています。
モジュールの定義
モジュールは、モジュール識別子で定義されます。 一般的な構文と例は次のとおりです。
構文
-module(ModuleName)
*ModuleName* は、ファイル名から拡張子 *.erl* を引いたものと同じである必要があります。 そうしないと、コードのロードが意図したとおりに機能しません。
例
-module(helloworld)
これらのモジュールについては、次の章で詳しく説明します。これは、モジュールの定義方法の基本的な理解を得るためのものです。
Erlangのインポートステートメント
Erlangでは、既存のErlangモジュールの機能を使用したい場合、import文を使用できます。 インポート文の一般的な形式は、次のプログラムに描かれています-
例
-import (modulename, [functionname/parameter]).
どこで、
- Modulename -これは、インポートする必要があるモジュールの名前です。
- functionname/parameter -インポートする必要があるモジュール内の関数。
importステートメントを使用するように、hello worldプログラムの作成方法を変更しましょう。 この例は、次のプログラムに示すとおりです。
例
% hello world program
-module(helloworld).
-import(io,[fwrite/1]).
-export([start/0]).
start() ->
fwrite("Hello, world!\n").
上記のコードでは、importキーワードを使用してライブラリ「io」、具体的には fwrite 関数をインポートしています。 そのため、fwrite関数を呼び出すたびに、どこでも io モジュール名を指定する必要はありません。
Erlangのキーワード
キーワードは、Erlangの予約語であり、意図された目的以外の目的には使用しないでください。 以下は、Erlangのキーワードのリストです。
after | and | andalso | band |
begin | bnot | bor | bsl |
bsr | bxor | case | catch |
cond | div | end | fun |
if | let | not | of |
or | orelse | receive | rem |
try | when | xor |
Erlangのコメント
コメントは、コードを文書化するために使用されます。 単一行コメントは、行の任意の位置で*%*記号を使用して識別されます。 以下は、同じ例です-
例
% hello world program
-module(helloworld).
% import function used to import the io module
-import(io,[fwrite/1]).
% export function used to ensure the start function can be accessed.
-export([start/0]).
start() ->
fwrite("Hello, world!\n").
アーラン-シェル
Erlangシェルは、式のテストに使用されます。 したがって、アプリケーション自体で実際にテストされる前に、シェルでテストを非常に簡単に実行できます。
次の例は、加算式をシェルで使用する方法を示しています。 ここで注意する必要があるのは、式がドット(。)区切り文字で終わる必要があるということです。
コマンドが実行された後、シェルは別のプロンプトを印刷します。今回はコマンド番号2の場合です(新しいコマンドが入力されるたびにコマンド番号が増加するため)。
次の関数は、Erlangシェルで使用される最も一般的な関数です。
- * b()*-現在の変数バインディングを出力します。
- 構文-b()。
- 例-以下は、関数の使用方法の例です。 最初に、 Str という変数が定義されます。この変数の値は abcd です。 次に、* b()*を使用して、バインドされたすべての変数を表示します。
- * f()*-現在のすべての変数バインディングを削除します。
- 構文-f()。
- 例-以下は、関数の使用方法の例です。 最初に、値abcdを持つStrという変数が定義されます。 次に、f()を使用してStr変数バインディングを削除します。 次に、b()が呼び出され、バインディングが正常に削除されたことを確認します。
- * f(x)*-特定の変数のバインディングを削除します。
- 構文-f(x)。 ここで、x –は、バインディングを削除する必要がある変数です。
- 例-以下は、関数の使用方法の例です。 最初に、StrおよびStr1という変数が定義されます。 次に、f(Str)を使用してStr変数バインディングを削除します。 次に、b()が呼び出され、バインディングが正常に削除されたことを確認します。
- * h()*-シェルで実行されたすべてのコマンドの履歴リストを出力します。
- 構文-h()。
- 例-シェルで実行されたコマンドの履歴を出力するh()コマンドの例を次のスクリーンショットに示します。
- * history(N)*-履歴リストに保持する以前のコマンドの数をNに設定します。 前の番号が返されます。 デフォルトの数は20です。
- 構文-history(N)。 ここで、N-は、コマンド履歴リストを制限する必要がある番号です。
- 例-history(N)コマンドの例を次のスクリーンショットに示します。
- * e(N)*-Nが正の場合、コマンドNを繰り返します。 負の場合、N ^ th ^前のコマンドが繰り返されます(つまり、e(-1)は前のコマンドを繰り返します)。
- 構文-e(N)。 ここで、N –はリストのN ^ th ^位置のコマンドです。
- 例-e(N)コマンドの例を以下に示します。 e(-1)コマンドを実行したため、history(5)であった前のコマンドを実行します。
アーラン-データ型
プログラミング言語では、さまざまなタイプの情報を保存するためにいくつかの変数を使用する必要があります。 変数は、値を保存するために予約されたメモリの場所に他なりません。 これは、変数を作成するときに、その変数に関連付けられた値を保存するためにメモリ内にスペースを確保することを意味します。
文字列、文字、ワイド文字、整数、浮動小数点、ブールなどのさまざまなデータ型の情報を保存することができます。 変数のデータ型に基づいて、オペレーティングシステムはメモリを割り当て、予約メモリに保存できるものを決定します。
組み込みデータ型
Erlangは、さまざまな組み込みデータ型を提供します。 以下は、Erlangで定義されているデータ型のリストです-
- Number -Erlangには、整数と浮動小数点の2種類の数値リテラルがあります。
- Atom -アトムはリテラル、名前付きの定数です。 小文字で始まっていない場合、または英数字、アンダースコア(_)、または@以外の文字が含まれている場合、アトムは単一引用符( ')で囲まれます。
- ブール-Erlangのブールデータ型は2つの予約されたアトムです:trueとfalse。
- ビット文字列-ビット文字列は、型なしメモリの領域を格納するために使用されます。
- タプル-タプルは、固定数の用語を持つ複合データ型です。 タプルの各Termは要素として呼び出されます。 要素の数はタプルのサイズと言われています。
- Map -マップは、可変値のキーと値の関連付けを持つ複合データ型です。 マップ内の各キーと値の関連付けは、関連付けペアと呼ばれます。 ペアのキーと値の部分は要素と呼ばれます。 アソシエーションペアの数は、マップのサイズと呼ばれます。
- リスト-リストは、可変数の用語を持つ複合データ型です。 リスト内の各用語は要素と呼ばれます。 要素の数は、リストの長さと言われます。
注-上記のリストのどこにも文字列型が表示されないことに驚かれることでしょう。 これは、Erlangで排他的に定義されている文字列データ型がないためです。 しかし、次の章で文字列をどのように使用できるかを見ていきます。
以下に、各データ型の使用方法の例を示します。 繰り返しますが、各データ型については、次の章で詳しく説明します。 これは、上記のデータ型の簡単な説明を知るためのものです。
数
数値データ型の使用方法の例を次のプログラムに示します。 このプログラムは、2つの整数の追加を示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~w",[1+1]).
上記のプログラムの出力は次のようになります-
出力
2
Atom
原子は小文字で始まり、小文字と大文字、数字、アンダースコア*(_)および「アット」記号(@)*を含めることができます。 アトムを一重引用符で囲むこともできます。
アトムデータ型の使用方法の例を、次のプログラムに示します。 このプログラムでは、atom1と呼ばれるアトムを作成しています。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite(atom1).
上記のプログラムの出力は次のようになります-
出力
atom1
ブール値
ブールデータ型の使用方法の例を次のプログラムに示します。 この例では、2つの整数を比較し、結果のブール値をコンソールに出力します。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite(2 =< 3).
上記のプログラムの出力は次のようになります-
- 出力 *
true
ビット列
ビット文字列データ型の使用方法の例を次のプログラムに示します。 このプログラムは、2ビットで構成されるビット文字列を定義します。* binary_to_list *はErlangで定義された組み込み関数で、ビット文字列をリストに変換するために使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
Bin1 = <<10,20>>,
X = binary_to_list(Bin1),
io:fwrite("~w",[X]).
上記のプログラムの出力は次のようになります-
出力
[10,20]
タプル
Tupleデータ型の使用方法の例を次のプログラムに示します。
ここでは、3つの用語を持つ Tuple P を定義しています。 tuple_size はErlangで定義された組み込み関数で、タプルのサイズを決定するために使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
P = {john,24,{june,25}} ,
io:fwrite("~w",[tuple_size(P)]).
上記のプログラムの出力は次のようになります-
出力
3
Map
Mapデータ型の使用方法の例を次のプログラムに示します。
ここでは、2つのマッピングを持つ Map M1 を定義しています。 map_size は、Erlangで定義された組み込み関数であり、マップのサイズを決定するために使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
M1 = #{name=>john,age=>25},
io:fwrite("~w",[map_size(M1)]).
上記のプログラムの出力は次のようになります-
出力
2
List
Listデータ型の使用方法の例を、次のプログラムに示します。
ここでは、3つのアイテムを持つ List L を定義しています。 長さは、Erlangで定義された組み込み関数であり、リストのサイズを決定するために使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
L = [10,20,30] ,
io:fwrite("~w",[length(L)]).
上記のプログラムの出力は次のようになります-
出力
3
アーラン-変数
Erlangでは、すべての変数は「=」ステートメントでバインドされます。 すべての変数は大文字で始まる必要があります。 他のプログラミング言語では、「=」記号が割り当てに使用されますが、Erlangの場合は使用されません。 前述のように、変数は「=」ステートメントを使用して定義されます。
Erlangで注意すべき重要な点の1つは、変数が不変であるということです。つまり、変数の値を変更するには、変数を破棄して再作成する必要があります。
Erlangの次の基本的な変数は、最後の章で説明されています-
- 数字-これは、整数または浮動小数点数を表すために使用されます。 例は10です。
- ブール-これはブール値を表し、trueまたはfalseのいずれかです。
- ビット文字列-ビット文字列は、型なしメモリの領域を格納するために使用されます。 例は<< 40,50 >>です。
- タプル-タプルは、固定数の用語を持つ複合データ型です。 例は\ {40,50}です。
- Map -マップは、可変値のキーと値の関連付けを持つ複合データ型です。 マップ内の各キーと値の関連付けは、関連付けペアと呼ばれます。 例は\ {type ⇒ person、age ⇒ 25}です。
- リスト-リストは、可変数の用語を持つ複合データ型です。 例は[40,40]です。
可変宣言
変数を定義する一般的な構文は次のとおりです-
構文
var-name = var-value
どこで、
- var-name -これは変数の名前です。
- var-value -これは変数にバインドされた値です。
以下は、変数宣言の例です-
例
-module(helloworld).
-export([start/0]).
start() ->
X = 40,
Y = 50,
Result = X + Y,
io:fwrite("~w",[Result]).
上記の例では、2つの変数があります。1つはXで値40にバインドされ、次はYで値50にバインドされています。 Resultという別の変数は、XとYの追加にバインドされます。
上記のプログラムの出力は次のようになります-
出力
90
変数の命名
説明したように、変数名は大文字で始まる必要があります。 小文字で宣言された変数の例を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
X = 40,
Y = 50,
result = X + Y,
io:fwrite("~w",[Result]).
上記のプログラムをコンパイルしようとすると、次のコンパイル時エラーが発生します。
出力
helloworld.erl:8: variable 'Result' is unbound
第二に、すべての変数は一度しか割り当てることができません。 変数を複数回割り当てる例を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
X = 40,
Y = 50,
X = 60,
io:fwrite("~w",[X]).
上記のプログラムをコンパイルしようとすると、次のコンパイル時エラーが表示されます。
出力
helloworld.erl:6: Warning: variable 'Y' is unused
helloworld.erl:7: Warning: no clause will ever match
helloworld.erl:7: Warning: the guard for this clause evaluates to 'false'
変数の印刷
このセクションでは、変数を印刷するさまざまな機能の使用方法について説明します。
io:fwrite関数を使用する
これ(io:fwrite)が上記のすべてのプログラムで使用されるのを見たことがあるでしょう。 fwrite 関数は、プログラム内の変数の値を出力するために使用できる「io」モジュールまたはErlangの一部です。
次の例は、fwriteステートメントで使用できるいくつかのパラメーターを示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
X = 40.00,
Y = 50.00,
io:fwrite("~f~n",[X]),
io:fwrite("~e",[Y]).
上記のプログラムの出力は次のようになります-
出力
40.000000
5.00000e+1
上記のプログラムについて、以下のポインターに注意する必要があります。
- 〜-この文字は、出力のために何らかのフォーマットを実行する必要があることを象徴しています。
- *〜f *-引数は[-] ddd.dddとして記述される浮動小数点数で、精度は小数点以下の桁数です。 デフォルトの精度は6で、1未満にはできません。
- 〜n *-これは、新しい行に *println することです。
- *〜e *-引数は[-] d.ddde&plus; -dddとして記述される浮動小数点数で、精度は書き込まれた桁数です。 デフォルトの精度は6で、2未満にはできません。
アーラン-オペレーター
演算子は、特定の数学的または論理的な操作を実行するようコンパイラーに指示する記号です。
Erlangには次のタイプの演算子があります-
- 算術演算子
- 関係演算子
- 論理演算子
- ビットごとの演算子
算術演算子
Erlang言語は、すべての言語として通常の算術演算子をサポートしています。 Erlangで使用できる算術演算子は次のとおりです。
リンク:/erlang/erlang_arithmatic_operators [例を表示]
Operator | Description | Example |
---|---|---|
PLUS | Addition of two operands | 1 PLUS 2 will give 3 |
− | Subtracts second operand from the first | 1 - 2 will give -1 |
* | Multiplication of both operands | 2* 2 will give 4 |
/ | Division of numerator by denominator | 2/2 will give 1 |
rem | Remainder of dividing the first number by the second | 3 rem 2 will give 1 |
div | The div component will perform the division and return the integer component. | 3 div 2 will give 1 |
関係演算子
関係演算子を使用すると、オブジェクトを比較できます。 Erlangで使用できる関係演算子は次のとおりです。
リンク:/erlang/erlang_relational_operators [例を表示]
Operator | Description | Example |
---|---|---|
== | Tests the equality between two objects | 2 = 2 will give true |
/= | Tests the difference between two objects | 3/= 2 will give true |
< | Checks to see if the left object is less than the right operand. | 2 < 3 will give true |
=< | Checks to see if the left object is less than or equal to the right operand. | 2 =<3 will give true |
> | Checks to see if the left object is greater than the right operand. | 3 > 2 will give true |
>= | Checks to see if the left object is greater than or equal to the right operand. | 3 >= 2 will give true |
論理演算子
これらの論理演算子は、ブール式を評価するために使用されます。 Erlangで使用できる論理演算子は次のとおりです。
リンク:/erlang/erlang_logical_operators [例を表示]
Operator | Description | Example |
---|---|---|
or | This is the logical “or” operator | true or true will give true |
and | This is the logical “and” operator | True and false will give false |
not | This is the logical “not” operator | not false will give true |
xor | This is the logical exclusive “xor” operator | True xor false will give true |
ビット演算子
Erlangは4つのビット演算子を提供します。 Erlangで使用できるビット演算子は次のとおりです。
リンク:/erlang/erlang_bitwise_operators [例を表示]
Sr.No. | Operator & Description |
---|---|
1 |
band これはビット単位の「and」演算子です |
2 |
bor これはビット単位の「or」演算子です |
3 |
bxor これはビット単位の「xor」または排他的論理和演算子です |
4 |
bnot これはビットごとの否定演算子です |
以下は、これらの演算子を示す真理値表です-
p | q | p & q | p | q |
---|---|---|---|---|
p ^ q | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
0 | 1 | 0 | 0 | 1 |
演算子の優先順位
次の表に、アーラン演算子の演算子の優先順位を、優先度の降順と結合性の順に示します。 演算子の優先順位と結合性を使用して、括弧なしの式の評価順序を決定します。
Operators | Associativity |
---|---|
: | |
# | |
bnot,not | |
/,*,div,rem,band,and | Left associative |
PLUS,-,bor,bxor,or,xor | Left associative |
==,/=,=<,<,>=,> |
アーラン-ループ
Erlangは関数型プログラミング言語であり、すべての関数型プログラミング言語について覚えておく必要があるのは、ループの構造を提供しないことです。 代わりに、関数型プログラミングは再帰と呼ばれる概念に依存しています。
whileステートメントの実装
Erlangには直接のwhileステートメントはありませんので、whileステートメントの実装を実行するには、Erlangで利用可能な再帰手法を使用する必要があります。
他のプログラミング言語で行われているのと同じwhileループの実装に従うようにします。 次に、一般的なフローを示します。
Erlangで while ループを実装するために再帰を使用する方法の例を見てみましょう。
例
-module(helloworld).
-export([while/1,while/2, start/0]).
while(L) -> while(L,0).
while([], Acc) -> Acc;
while([_|T], Acc) ->
io:fwrite("~w~n",[Acc]),
while(T,Acc+1).
start() ->
X = [1,2,3,4],
while(X).
上記のプログラムについて、次のキーポイントに注意する必要があります-
- whileループの実装をシミュレートするwhileと呼ばれる再帰関数を定義します。
- 例として、変数Xで定義された値のリストをwhile関数に入力します。
- while関数は各リスト値を取得し、中間値を変数「Acc」に保存します。
- リスト内の各値に対してwhileループが再帰的に呼び出されます。
上記のコードの出力は次のようになります-
出力
0
1
2
3
声明のために
Erlangには直接の for ステートメントはないため、 for ステートメントの実装を実行するには、Erlangで使用可能な再帰手法を使用する必要があります。
他のプログラミング言語で行われているのと同じ for ループの実装に従うようにします。 以下は、順守すべき一般的な流れです。
Erlangで再帰を使用して for ループを実装する方法の例を見てみましょう。
例
-module(helloworld).
-export([for/2,start/0]).
for(0,_) ->
[];
for(N,Term) when N > 0 ->
io:fwrite("Hello~n"),
[Term|for(N-1,Term)].
start() ->
for(5,1).
上記のプログラムについて、次のキーポイントに注意する必要があります-
- * forループ*の実装をシミュレートする再帰関数を定義しています。
- 「for」関数内でガードを使用して、Nの値または制限が正の値であることを確認しています。
- 各再帰でNの値を減らすことにより、for関数を再帰的に呼び出します。
上記のコードの出力は次のようになります-
出力
Hello
Hello
Hello
Hello
Hello
アーラン-意思決定
意思決定構造では、プログラマーが、プログラムによって評価またはテストされる1つ以上の条件、および条件が true であると判断された場合に実行されるステートメント、およびオプションで実行される他のステートメントを指定する必要があります条件が false であると判断された場合。
以下は、ほとんどのプログラミング言語で見られる典型的な意思決定構造の一般的な形式です-
Erlangプログラミング言語は、次のタイプの意思決定ステートメントを提供します。
Sr.No. | Statement & Description |
---|---|
1 |
|
2 |
|
3 |
1つの if または else if ステートメントを別の if または else if ステートメント内で使用できます。 |
4 |
caseステートメントの出力に基づいて式を実行するために使用できます。 |
Erlang-関数
Erlangは関数型プログラミング言語として知られているため、Erlangで関数がどのように機能するかに重点を置くことが期待されます。 この章では、Erlangの機能を使用してできることをすべて説明します。
関数を定義する
関数宣言の構文は次のとおりです-
構文
FunctionName(Pattern1… PatternN) ->
Body;
どこで、
- FunctionName -関数名はアトムです。
- Pattern1…PatternN -各引数はパターンです。 引数の数Nは、関数のアリティです。 関数は、モジュール名、関数名、およびアリティによって一意に定義されます。 つまり、同じ名前で同じモジュール内の2つの関数が、異なるアリティを持つ2つの関数です。
- ボディ-句のボディは、コンマ(、)で区切られた一連の式で構成されます。
次のプログラムは、関数の使用の簡単な例です-
例
-module(helloworld).
-export([add/2,start/0]).
add(X,Y) ->
Z = X+Y,
io:fwrite("~w~n",[Z]).
start() ->
add(5,6).
次のポインタは、上記のプログラムについて注意する必要があります-
- 2つの関数を定義しています。1つは2つのパラメーターを取る add と呼ばれ、もう1つは start 関数です。
- 両方の機能は、エクスポート機能で定義されています。 これを行わないと、関数を使用できなくなります。
- 1つの関数を別の関数内で呼び出すことができます。 ここでは、start関数からadd関数を呼び出しています。
上記のプログラムの出力は次のようになります-
出力
11
無名関数
匿名関数は、名前が関連付けられていない関数です。 Erlangには、匿名関数を定義する機能があります。 次のプログラムは、無名関数の例です。
例
-module(helloworld).
-export([start/0]).
start() ->
Fn = fun() ->
io:fwrite("Anonymous Function") end,
Fn().
上記の例について、次の点に注意する必要があります-
- 無名関数は* fun()*キーワードで定義されます。
- 関数はFnという変数に割り当てられます。
- 関数は変数名を介して呼び出されます。
上記のプログラムの出力は次のようになります-
出力
Anonymous Function
複数の引数を持つ関数
Erlang関数は、0個以上のパラメーターで定義できます。 関数のオーバーロードも可能です。パラメーターの数が異なる限り、同じ名前の関数を複数回定義できます。
次の例では、関数demoは各関数定義の複数の引数で定義されています。
例
-module(helloworld).
-export([add/2,add/3,start/0]).
add(X,Y) ->
Z = X+Y,
io:fwrite("~w~n",[Z]).
add(X,Y,Z) ->
A = X+Y+Z,
io:fwrite("~w~n",[A]).
start() ->
add(5,6),
add(5,6,6).
上記のプログラムでは、add関数を2回定義しています。 ただし、最初のadd関数の定義は2つのパラメーターを受け取り、2番目の関数は3つのパラメーターを受け取ります。
上記のプログラムの出力は次のようになります-
出力
11
17
ガードシーケンスを使用する機能
Erlangの関数には、ガードシーケンスを持つ機能もあります。 これらは、trueと評価された場合にのみ関数を実行する式に他なりません。
ガードシーケンスを使用した関数の構文は、次のプログラムに示されています。
構文
FunctionName(Pattern1… PatternN) [when GuardSeq1]->
Body;
どこで、
- FunctionName -関数名はアトムです。
- Pattern1…PatternN -各引数はパターンです。 引数の数Nは、関数のアリティです。 関数は、モジュール名、関数名、およびアリティによって一意に定義されます。 つまり、同じ名前で同じモジュール内の2つの関数が、異なるアリティを持つ2つの関数です。
- ボディ-句のボディは、コンマ(、)で区切られた一連の式で構成されます。
- GuardSeq1 -これは、関数が呼び出されたときに評価される式です。
次のプログラムは、ガードシーケンスを使用した関数の使用の簡単な例です。
例
-module(helloworld).
-export([add/1,start/0]).
add(X) when X>3 ->
io:fwrite("~w~n",[X]).
start() ->
add(4).
上記のプログラムの出力は-
出力
4
add関数が* add(3)*として呼び出された場合、プログラムはエラーになります。
Erlang-モジュール
モジュールは、単一の名前で単一のファイルに再グループ化された一連の関数です。 さらに、Erlangのすべての関数はモジュールで定義する必要があります。
プログラムの実行時にデフォルトのモジュールがロードされるため、算術演算子、論理演算子、ブール演算子などの基本的な機能のほとんどはすでに利用可能です。 使用するモジュールで定義されている他のすべての関数は、 Module:Function (Arguments)の形式で呼び出す必要があります。
モジュールの定義
モジュールを使用すると、関数と属性の2種類のことを宣言できます。 属性は、モジュールの名前、外部から見える機能、コードの作成者など、モジュール自体を記述するメタデータです。 この種のメタデータは、コンパイラにジョブの実行方法に関するヒントを提供し、ソースを参照することなくコンパイルされたコードから有用な情報を取得できるため便利です。
関数宣言の構文は次のとおりです-
構文
-module(modulename)
ここで、 modulename はモジュールの名前です。 これは、モジュール内のコードの最初の行でなければなりません。
次のプログラムは、 helloworld というモジュールの例を示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("Hello World").
上記のプログラムの出力は-
出力
Hello World
モジュール属性
モジュール属性は、モジュールの特定のプロパティを定義します。 モジュール属性は、タグと値で構成されます。
属性の一般的な構文は次のとおりです-
構文
-Tag(Value)
属性の使用方法の例は、次のプログラムに示されています-
例
-module(helloworld).
-author("TutorialPoint").
-version("1.0").
-export([start/0]).
start() ->
io:fwrite("Hello World").
上記のプログラムは、authorとversionと呼ばれる2つのカスタム属性を定義します。これらには、それぞれプログラムの作成者とプログラムのバージョン番号が含まれています。
上記のプログラムの出力は-
出力
Hello World
事前作成された属性
Erlangには、モジュールにアタッチできるビルド済みの属性がいくつかあります。 それらを見てみましょう。
輸出する
exports属性は、他のモジュールで使用するためにエクスポートする関数とアリティのリストを取ります。 モジュールインターフェイスを定義します。 これは、以前のすべての例ですでに見ています。
構文
export([FunctionName1/FunctionArity1,.,FunctionNameN/FunctionArityN])
どこで、
- FunctionName -これはプログラム内の関数の名前です。
- FunctionArity -これは、関数に関連付けられているパラメーターの数です。
例
-module(helloworld).
-author("TutorialPoint").
-version("1.0").
-export([start/0]).
start() ->
io:fwrite("Hello World").
上記のプログラムの出力は次のようになります-
出力
Hello World
インポート
import属性は、他のモジュールから関数をインポートしてローカルとして使用するために使用されます。
構文
-import (modulename , [functionname/parameter]).
どこで、
- Modulename -これは、インポートする必要があるモジュールの名前です。
- functionname/parameter -インポートする必要があるモジュール内の関数。
例
-module(helloworld).
-import(io,[fwrite/1]).
-export([start/0]).
start() ->
fwrite("Hello, world!\n").
上記のコードでは、importキーワードを使用してライブラリ「io」、特にfwrite関数をインポートしています。 したがって、fwrite関数を呼び出すたびに、どこでもioモジュール名を言及する必要はありません。
上記のプログラムの出力は次のようになります-
出力
Hello, world!
アーラン-再帰
再帰はErlangの重要な部分です。 まず、階乗プログラムを実装することにより、単純な再帰を実装する方法を見てみましょう。
例
-module(helloworld).
-export([fac/1,start/0]).
fac(N) when N == 0 -> 1;
fac(N) when N > 0 -> N*fac(N-1).
start() ->
X = fac(4),
io:fwrite("~w",[X]).
上記のプログラムについては、次のことに注意する必要があります-
- 最初にfac(N)という関数を定義しています。
- fac(N)を再帰的に呼び出すことにより、再帰関数を定義できます。
上記のプログラムの出力は-
出力
24
再帰への実用的なアプローチ
このセクションでは、Erlangでのさまざまなタイプの再帰とその使用法を詳細に理解します。
長さの再帰
再帰へのより実用的なアプローチは、リストの長さを決定するために使用される簡単な例で見ることができます。 リストには、[1,2,3,4]などの複数の値を含めることができます。 再帰を使用して、リストの長さを取得する方法を見てみましょう。
例
-module(helloworld).
-export([len/1,start/0]).
len([]) -> 0;
len([_|T]) -> 1 + len(T).
start() ->
X = [1,2,3,4],
Y = len(X),
io:fwrite("~w",[Y]).
上記のプログラムについては、次のことに注意する必要があります-
- 最初の関数* len([])*は、リストが空の場合の特別な場合の条件に使用されます。
- 長さ1のリストは [X | []] として定義され、長さ2のリストは* [Xとして定義されるため、1つ以上の要素のリストと一致する [H | T] パターン| [Y | []]] *。 2番目の要素はリスト自体であることに注意してください。 つまり、最初の要素を数えるだけで、関数は2番目の要素で自分自身を呼び出すことができます。 リスト内の各値は、長さ1としてカウントされます。
上記のプログラムの出力は次のようになります-
出力
4
末尾再帰
末尾再帰の仕組みを理解するために、前のセクションの次のコードの仕組みを理解しましょう。
構文
len([]) -> 0;
len([_|T]) -> 1 + len(T).
1 + len(Rest)に対する答えは、len(Rest)の答えを見つける必要があります。 関数len(Rest)自体は、別の関数呼び出しの結果を見つける必要がありました。 足し算は最後の足しが見つかるまで積み上げられ、そのときだけ最終的な結果が計算されます。
テール再帰は、発生する操作を減らすことで、このような操作の積み重ねをなくすことを目的としています。
これを実現するために、追加の一時変数を関数のパラメーターとして保持する必要があります。 前述の一時変数はアキュムレータと呼ばれることもあり、計算の結果を保存する場所として機能し、呼び出しの増加を制限します。
末尾再帰の例を見てみましょう-
例
-module(helloworld).
-export([tail_len/1,tail_len/2,start/0]).
tail_len(L) -> tail_len(L,0).
tail_len([], Acc) -> Acc;
tail_len([_|T], Acc) -> tail_len(T,Acc+1).
start() ->
X = [1,2,3,4],
Y = tail_len(X),
io:fwrite("~w",[Y]).
上記のプログラムの出力は-
出力
4
複製する
再帰の例を見てみましょう。 今回は、最初のパラメーターとして整数を、次に2番目のパラメーターとして他の用語を使用する関数を作成してみましょう。 その後、整数で指定された数だけ用語のコピーのリストを作成します。
この例がどのように見えるか見てみましょう-
-module(helloworld).
-export([duplicate/2,start/0]).
duplicate(0,_) ->
[];
duplicate(N,Term) when N > 0 ->
io:fwrite("~w,~n",[Term]),
[Term|duplicate(N-1,Term)].
start() ->
duplicate(5,1).
上記のプログラムの出力は次のようになります-
出力
1,
1,
1,
1,
1,
リストの反転
Erlangで再帰を使用できる範囲はありません。 再帰を使用してリストの要素を逆にする方法を見てみましょう。 次のプログラムを使用して、これを達成できます。
例
-module(helloworld).
-export([tail_reverse/2,start/0]).
tail_reverse(L) -> tail_reverse(L,[]).
tail_reverse([],Acc) -> Acc;
tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).
start() ->
X = [1,2,3,4],
Y = tail_reverse(X),
io:fwrite("~w",[Y]).
上記のプログラムの出力は次のようになります-
出力
[4,3,2,1]
上記のプログラムについては、次のことに注意する必要があります-
- ここでも、一時変数の概念を使用して、リストの各要素をAccという変数に格納します。
- 次に tail_reverse を再帰的に呼び出しますが、今回は最後の要素が新しいリストに最初に配置されるようにします。
- 次に、リスト内の各要素に対してtail_reverseを再帰的に呼び出します。
アーラン-数字
Erlangには、整数と浮動小数点の2種類の数値リテラルがあります。 以下は、Erlangで整数と浮動小数点を使用する方法を示すいくつかの例です。
整数-数値データ型を整数として使用する方法の例を次のプログラムに示します。 このプログラムは、2つの整数の追加を示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~w",[1+1]).
上記のプログラムの出力は次のようになります-
出力
2
フロート-数値データ型をフロートとして使用する方法の例を次のプログラムに示します。 このプログラムは、2つの整数の追加を示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~w",[1.1+1.2]).
上記のプログラムの出力は次のようになります-
出力
2.3
浮動小数点数と指数数の表示
*fwrite* メソッドを使用して値をコンソールに出力する場合、数値を浮動小数点または指数として出力するために使用できるフォーマットパラメーターがあります。 これを達成する方法を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~f~n",[1.1+1.2]),
io:fwrite("~e~n",[1.1+1.2]).
上記のプログラムの出力は次のようになります-
出力
2.300000
2.30000e+0
上記のプログラムについて、次の重要事項に注意する必要があります-
- 〜fオプションを指定すると、引数は [-] ddd.ddd として記述される浮動小数点数になります。精度は小数点以下の桁数です。 デフォルトの精度は6です。
- 〜eオプションが指定されている場合、引数が [-] d.ddde + -ddd として記述された浮動小数点数であることを意味します。精度は書き込まれた桁数です。 デフォルトの精度は6です。
数値の数学関数
次の数学関数は、Erlangで数値に使用できます。 Erlangのすべての数学関数は、数学ライブラリに存在することに注意してください。 したがって、以下の例はすべてimportステートメントを使用して、数学ライブラリのすべてのメソッドをインポートします。
シニア
数学関数と説明
1
リンク:/erlang/erlang_sin [sin]
このメソッドは、指定された値のサインを返します。
2
リンク:/erlang/erlang_cos [cos]
このメソッドは、指定された値のコサインを返します。
3
リンク:/erlang/erlang_tan [tan]
このメソッドは、指定された値のタンジェントを返します。
4
リンク:/erlang/erlang_asin [asin]
このメソッドは、指定された値のアークサインを返します。
5
リンク:/erlang/erlang_acos [acos]
このメソッドは、指定された値のアークコサインを返します。
6
リンク:/erlang/erlang_atan [atan]
このメソッドは、指定された値のアークタンジェントを返します。
7
リンク:/erlang/erlang_exp [exp]
メソッドは、指定された値の指数を返します。
8
リンク:/erlang/erlang_log [log]
このメソッドは、指定された値の対数を返します。
9
リンク:/erlang/erlang_abs [abs]
このメソッドは、指定された数値の絶対値を返します。
10
リンク:/erlang/erlang_float [float]
このメソッドは、数値を浮動小数点値に変換します。
11
リンク:/erlang/erlang_is_float [Is_float]
このメソッドは、数値が浮動小数点値かどうかを確認します。
12
リンク:/erlang/erlang_is_integer [Is_Integer]
このメソッドは、数値が整数値かどうかを確認します。
アーラン-文字列
文字列リテラルは、文字列テキストを引用符で囲むことにより、Erlangで構築されます。 Erlangの文字列は、「Hello World」などの二重引用符を使用して作成する必要があります。
以下は、Erlangでの文字列の使用例です-
例
-module(helloworld).
-export([start/0]).
start() ->
Str1 = "This is a string",
io:fwrite("~p~n",[Str1]).
上記の例は、 Str1 という文字列変数を作成します。 文字列「This is a string」が変数に割り当てられ、それに応じて表示されます。
上記のプログラムの出力は次のようになります-
出力
“This is a string”
次に、文字列に使用できるさまざまな*操作*について説明します。 文字列操作の場合、文字列ライブラリも含める必要があることに注意してください。
Sr.No | String Methods & Description |
---|---|
1 |
このメソッドは、特定の文字列の長さを返します。 |
2 |
このメソッドは、ある文字列が別の文字列と等しいかどうかのブール値を返します。 |
3 |
このメソッドは2つの文字列を連結し、連結された文字列を返します。 |
4 |
このメソッドは、文字列内の文字のインデックス位置を返します。 |
5 |
このメソッドは、文字列内のサブ文字列のインデックス位置を返します。 |
6 |
このメソッドは、開始位置と開始位置からの文字数に基づいて、元の文字列からサブ文字列を返します。 |
7 |
このメソッドは、開始位置と開始位置からの文字数に基づいて、元の文字列からサブ文字列を返します。 |
末尾の文字で左
このメソッドは、文字数に基づいて文字列の左からサブ文字列を返します。 ただし、数値が文字列の長さよりも大きい場合、末尾の文字を含めるオプションがあります。
構文
left(str1,number,$character)
パラメーター
- str1 -これは、サブ文字列を抽出する必要がある文字列です。
- Number -これは、サブストリングに存在する必要がある文字の数です。
- $ Character -末尾の文字として含める文字。
戻り値
文字列の左側と数値に基づいて、元の文字列からサブ文字列を返します。
例えば
-module(helloworld).
-import(string,[left/3]).
-export([start/0]).
start() ->
Str1 = "hello",
Str2 = left(Str1,10,$.),
io:fwrite("~p~n",[Str2]).
出力
上記のプログラムを実行すると、次の結果が得られます。
"hello....."
右
このメソッドは、文字数に基づいて文字列の右側からサブ文字列を返します。
構文
right(str1,number)
パラメーター
- str1 -これは、サブ文字列を抽出する必要がある文字列です。
- Number -これは、サブストリングに存在する必要がある文字の数です。
戻り値
文字列の右側と数値に基づいて、元の文字列から部分文字列を返します。
例えば
-module(helloworld).
-import(string,[right/2]).
-export([start/0]).
start() ->
Str1 = "hello World",
Str2 = right(Str1,2),
io:fwrite("~p~n",[Str2]).
出力
上記のプログラムを実行すると、次の結果が得られます。
“ld”
末尾の文字で右
このメソッドは、文字数に基づいて文字列の右側から部分文字列を返します。 ただし、数値が文字列の長さよりも大きい場合、末尾の文字を含めるオプションがあります。
構文
right(str1,number,$character)
パラメーター
- str1 -これは、サブ文字列を抽出する必要がある文字列です。
- Number -これは、サブストリングに存在する必要がある文字の数です。
- $ Character -末尾の文字として含める文字。
戻り値
文字列の右側と数値に基づいて、元の文字列からサブ文字列を返します。
例えば
-module(helloworld).
-import(string,[right/3]).
-export([start/0]).
start() ->
Str1 = "hello",
Str2 = right(Str1,10,$.),
io:fwrite("~p~n",[Str2]).
出力
上記のプログラムを実行すると、次の結果が得られます。
".....hello"
to_lower
このメソッドは、文字列を小文字で返します。
構文
to_lower(str1)
パラメーター
- str1 -これは、小文字に変換する必要がある文字列です。
戻り値
文字列を小文字で返します。
例えば
-module(helloworld).
-import(string,[to_lower/1]).
-export([start/0]).
start() ->
Str1 = "HELLO WORLD",
Str2 = to_lower(Str1),
io:fwrite("~p~n",[Str2]).
出力
上記のプログラムを実行すると、次の結果が得られます。
"hello world"
to_upper
このメソッドは、文字列を大文字で返します。
構文
to_upper(str1)
パラメーター
- str1 -これは、大文字に変換する必要がある文字列です。
- 戻り値-文字列を大文字で返します。
例えば
-module(helloworld).
-import(string,[to_upper/1]).
-export([start/0]).
start() ->
Str1 = "hello world",
Str2 = to_upper(Str1),
io:fwrite("~p~n",[Str2]).
出力
上記のプログラムを実行すると、次の結果が得られます。
"HELLO WORLD"
sub_string
文字列の部分文字列を返します。開始位置から文字列の最後まで、または停止位置までを含みます。
構文
sub_string(str1,start,stop)
パラメーター
- str1 -これは、サブ文字列を返す必要がある文字列です。
- start -これは部分文字列の開始位置です
- stop -これは部分文字列の停止位置です
戻り値
文字列の部分文字列を返します。開始位置から文字列の最後まで、または停止位置までを含みます。
例えば
-module(helloworld).
-import(string,[sub_string/3]).
-export([start/0]).
start() ->
Str1 = "hello world",
Str2 = sub_string(Str1,1,5),
io:fwrite("~p~n",[Str2]).
出力
上記のプログラムを実行すると、次の結果が得られます。
"hello"
アーラン-リスト
リストは、データ項目のコレクションを格納するために使用される構造です。 Erlangでは、リストは角括弧で値を囲むことによって作成されます。
以下は、Erlangで数字のリストを作成する簡単な例です。
例
-module(helloworld).
-export([start/0]).
start() ->
Lst1 = [1,2,3],
io:fwrite("~w~n",[Lst1]).
上記の例の出力は次のようになります-
出力
[1 2 3]
ここで、*リストで使用できる*さまざまな方法について説明します。 これらのメソッドを機能させるには、リストライブラリをインポートする必要があることに注意してください。
Sr.No | Method and Description |
---|---|
1 |
Pred(Elem)がリスト内のすべての要素Elemに対してtrueを返す場合はtrueを返し、そうでない場合はfalseを返します。 |
2 |
リスト内の少なくとも1つの要素Elemに対してPred(Elem)がtrueを返す場合、trueを返します。 |
3 |
List1の要素とList2の要素から構成される新しいリストList3を返します。 |
4 |
リストから要素を削除し、新しいリストを返します。 |
5 |
リストの最後の要素を削除します。 |
6 |
用語ElemのN個のコピーを含むリストを返します |
7 |
リストの最後の要素を返します |
8 |
最大値を持つリストの要素を返します。 |
9 |
リストに要素が存在するかどうかを確認します。 |
10 |
最小値を持つリストの要素を返します。 |
11 |
ListOfListsのすべてのサブリストをマージして形成されたソート済みリストを返します。 |
12 |
リストのN番目の要素を返します。 |
13 |
リストのN番目の末尾を返します。 |
14 |
要素のリストを逆にします。 |
15 |
要素のリストをソートします。 |
16 |
要素のサブリストを返します。 |
17 |
リスト内の要素の合計を返します。 |
Erlang-ファイルI/O
Erlangは、I/Oを操作するときに多くのメソッドを提供します。 ファイルに次の機能を提供するための簡単なクラスがあります-
- ファイルを読む
- ファイルへの書き込み
- ファイルがファイルかディレクトリかを確認する
Erlangのファイル操作メソッド
Erlangが提供するファイル操作のいくつかを見てみましょう。 これらの例の目的のために、次のテキスト行を含む NewFile.txt というファイルがあると想定します。
- 例1 *
- 例2 *
- 例3 *
このファイルは、次の例で読み取りおよび書き込み操作に使用されます。
ファイルの内容を一度に1行ずつ読み取る
ファイルの一般的な操作は、ファイルライブラリで使用可能なメソッドを使用して実行されます。 ファイルを読み込むには、まずopen操作を使用し、次にファイルライブラリの一部として利用可能なread操作を使用する必要があります。 これらの両方のメソッドの構文は次のとおりです。
構文
- ファイルを開く– Open(File、Mode)
- ファイルの読み取り– read(FileHandler、NumberofBytes)
パラメーター
- ファイル-これは、開く必要があるファイルの場所です。
- モード-これは、ファイルを開く必要があるモードです。
以下は利用可能なモードの一部です-
- 読み取り-存在する必要があるファイルが読み取り用に開かれます。
- 書き込み-ファイルは書き込み用に開かれます。 存在しない場合は作成されます。 ファイルが存在し、書き込みが読み取りと組み合わされていない場合、ファイルは切り捨てられます。
- 追加-ファイルは書き込み用に開かれ、存在しない場合は作成されます。 appendで開かれたファイルへのすべての書き込み操作は、ファイルの最後に行われます。
- Exclusive -書き込み用に開かれたファイルは、存在しない場合に作成されます。 ファイルが存在する場合、openは\ {error、exist}を返します。
- FileHandler -これはファイルへのハンドルです。 このハンドルは、 file:open 操作が使用されたときに返されるハンドルです。
- NumberofByte -これは、ファイルから読み取る必要がある情報のバイト数です。
戻り値
- * Open(File、Mode)*-操作が成功した場合、ファイルへのハンドルを返します。
- * read(FileHandler、NumberofBytes)*-ファイルから要求された読み取り情報を返します。
例えば
-module(helloworld).
-export([start/0]).
start() ->
{ok, File} = file:open("Newfile.txt",[read]),
Txt = file:read(File,1024 * 1024),
io:fwrite("~p~n",[Txt]).
出力-上記のプログラムを実行すると、次の結果が得られます。
Example1
ここで、ファイル操作に使用できる他の方法について説明します-
Sr.No. | Method & Description |
---|---|
1 |
ファイルのすべての内容を一度に読み取ることができるようにします。 |
2 |
内容をファイルに書き込むために使用されます。 |
3 |
既存のファイルのコピーを作成するために使用されます。 |
4 |
このメソッドは、既存のファイルを削除するために使用されます。 |
5 |
このメソッドは、特定のディレクトリの内容をリストダウンするために使用されます。 |
6 |
このメソッドは、新しいディレクトリを作成するために使用されます。 |
7 |
このメソッドは、既存のファイルの名前を変更するために使用されます。 |
8 |
このメソッドは、ファイルのサイズを決定するために使用されます。 |
9 |
このメソッドは、ファイルが実際にファイルであるかどうかを判別するために使用されます。 |
10 |
このメソッドは、ディレクトリが実際にディレクトリであるかどうかを判断するために使用されます。 |
アーラン-アトム
アトムはリテラルであり、名前を持つ定数です。 小文字で始まっていない場合、または英数字、アンダースコア(_)、@以外の文字が含まれている場合、アトムは単一引用符( ')で囲まれます。
次のプログラムは、Erlangで原子を使用する方法の例です。 このプログラムは、3つのアトム、atom1、atom_1、および「atom 1」をそれぞれ宣言します。 そのため、アトムを宣言できるさまざまな方法を見ることができます。
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite(atom1),
io:fwrite("~n"),
io:fwrite(atom_1),
io:fwrite("~n"),
io:fwrite('atom 1'),
io:fwrite("~n").
上記のプログラムの出力は次のようになります-
出力
atom1
atom_1
atom 1
Erlangで利用可能な原子の操作方法をいくつか見てみましょう。
Sr.No. | Methods and Description |
---|---|
1 |
このメソッドは、用語が実際にアトムかどうかを判断するために使用されます。 |
2 |
このメソッドは、アトムをリストに変換するために使用されます。 |
3 |
このメソッドは、リスト項目をアトムに変換するために使用されます。 |
4 |
このメソッドは、アトムをバイナリ値に変換するために使用されます。 |
5 |
このメソッドは、バイナリ値をアトム値に変換するために使用されます。 |
アーラン-地図
マップは、可変数のキーと値の関連付けを持つ複合データ型です。 マップ内の各キーと値の関連付けは、関連付けペアと呼ばれます。 ペアのキーと値の部分は要素と呼ばれます。 アソシエーションペアの数は、マップのサイズと呼ばれます。
Mapデータ型の使用方法の例を次のプログラムに示します。
ここでは、2つのマッピングを持つMap M1を定義しています。 map_size は、Erlangで定義された組み込み関数で、マップのサイズを決定するために使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
M1 = #{name=>john,age=>25},
io:fwrite("~w",[map_size(M1)]).
上記のプログラムの出力は次のようになります。
出力
2
マップに使用できる他の方法のいくつかは次のとおりです。
Sr.No. | Methods & Description |
---|---|
1 |
このメソッドは、リストからマップを生成するために使用されます。 |
2 |
このメソッドは、特定のキーがマップに存在するかどうかを見つけるために使用されます。 |
3 |
このメソッドは、マップ内の特定のキーの値を取得するために使用されます。 |
4 |
このメソッドは、特定のキーがマップ内のキーとして定義されているかどうかを判断するために使用されます。 |
5 |
このメソッドは、マップからすべてのキーを返すために使用されます。 |
6 |
この方法は、2つのマップをマージするために使用されます。 |
7 |
このメソッドは、キーと値のペアをマップに追加するために使用されます。 |
8 |
このメソッドは、マップからすべての値を返すために使用されます。 |
9 |
このメソッドは、マップからキー値を削除するために使用されます。 |
アーラン-タプル
タプルは、固定数の用語を持つ複合データ型です。 タプル内の各用語は要素と呼ばれます。 要素の数は、タプルのサイズと言われています。
Tupleデータ型の使用方法の例を次のプログラムに示します。
ここでは、3つの用語を持つ Tuple P を定義しています。 tuple_size は、Erlangで定義された組み込み関数で、タプルのサイズを決定するために使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
P = {john,24,{june,25}} ,
io:fwrite("~w",[tuple_size(P)]).
上記のプログラムの出力は次のようになります。
出力
3
タプルで使用できる操作をいくつか見てみましょう。
Sr.No. | Methods & Description |
---|---|
1 |
このメソッドは、提供された用語が実際にタプルであるかどうかを判別するために使用されます。 |
2 |
このメソッドは、リストをタプルに変換します。 |
3 |
このメソッドは、タプルをリストに変換します。 |
アーラン-レコード
Erlangには、レコードを作成するための追加機能があります。 これらのレコードはフィールドで構成されています。 たとえば、2つのフィールドを持つ個人レコードを定義できます。1つはIDで、もう1つは名前フィールドです。 Erlangでは、このレコードのさまざまなインスタンスを作成して、さまざまな名前とIDを持つ複数のユーザーを定義できます。
レコードを操作する方法を調べてみましょう。
レコードを作成する
レコードは、レコード識別子を使用して作成されます。 このレコード識別子では、レコードを構成するさまざまなフィールドを指定します。 一般的な構文と例を以下に示します。
構文
record(recordname , {Field1,Field2 ..Fieldn})
パラメーター
- レコード名-これはレコードに付けられた名前です。
- Field1、Field2 ..Fieldn -これらは、レコードを構成するさまざまなフィールドのリストです。
戻り値
None
例えば
-module(helloworld).
-export([start/0]).
-record(person, {name = "", id}).
start() ->
P = #person{name="John",id = 1}.
上記の例は、2つのフィールドを持つレコードの定義を示しています。1つはIDで、もう1つは名前です。 また、レコードは次のように構築されます-
構文
#recordname {fieldName1 = value1, fieldName2 = value2 .. fieldNameN = valueN}
レコードのインスタンスが定義されているときに、それぞれのフィールドに値を割り当てる場所。
レコードの値へのアクセス
特定のレコードのフィールドと値にアクセスするには、次の構文を使用する必要があります。
構文
#recordname.Fieldname
パラメーター
- レコード名-これはレコードに付けられた名前です。
- フィールド名-これは、アクセスする必要があるフィールドの名前です。
戻り値
フィールドに割り当てられた値。
例えば
-module(helloworld).
-export([start/0]).
-record(person, {name = "", id}).
start() ->
P = #person{name = "John",id = 1},
io:fwrite("~p~n",[P#person.id]),
io:fwrite("~p~n",[P#person.name]).
出力
上記のプログラムの出力は次のとおりです。
1
“John”
レコードの値を更新する
レコード値の更新は、値を特定のフィールドに変更してから、レコードを新しい変数名に割り当てることによって行われます。 一般的な構文と例を以下に示します。
構文
#recordname.Fieldname = newvalue
パラメーター
- レコード名-これはレコードに付けられた名前です。
- フィールド名-これは、アクセスする必要があるフィールドの名前です。
- newvalue -これは、フィールドに割り当てる必要がある新しい値です。
戻り値
フィールドに割り当てられた新しい値を持つ新しいレコード。
例えば
-module(helloworld).
-export([start/0]).
-record(person, {name = "", id}).
start() ->
P = #person{name = "John",id = 1},
P1 = P#person{name = "Dan"},
io:fwrite("~p~n",[P1#person.id]),
io:fwrite("~p~n",[P1#person.name]).
出力
上記のプログラムの出力は次のとおりです-
1
“Dan”
ネストされたレコード
Erlangには、レコードをネストする機能もあります。 次の例は、これらのネストされたレコードを作成する方法を示しています。
例えば
-module(helloworld).
-export([start/0]).
-record(person, {name = "", address}).
-record(employee, {person, id}).
start() ->
P = #employee{person = #person{name = "John",address = "A"},id = 1},
io:fwrite("~p~n",[P#employee.id]).
上記の例では、次のことに注意する必要があります-
- まず、名前と住所のフィールド値を持つ個人のレコードを作成します。
- 次に、フィールドとしての人物とidという追加フィールドを持つ従業員レコードを定義します。
出力
上記のプログラムの出力は次のとおりです。
1
アーラン-例外
アプリケーションの通常のフローを維持できるように、ランタイムエラーを処理するには、プログラミング言語で例外処理が必要です。 例外は通常、アプリケーションの通常のフローを中断します。これが、アプリケーションで例外処理を使用する必要がある理由です。
通常、Erlangで例外またはエラーが発生すると、次のメッセージが表示されます。
{"init terminating in do_boot", {undef,[{helloworld,start,[],[]},
{init,start_it,1,[]},{init,start_em,1,[]}]}}
クラッシュダンプはに書き込まれます-
erl_crash.dump
init terminating in do_boot ()
アーランでは、例外の3種類があります-
- エラー-* erlang:error(Reason)*を呼び出すと、現在のプロセスで実行が終了し、キャッチしたときに引数で呼び出された最後の関数のスタックトレースが含まれます。 これらは、上記のランタイムエラーを引き起こす種類の例外です。
- 存在-「内部」出口と「外部」出口の2種類の出口があります。 内部出口は、関数 exit/1 を呼び出すことによってトリガーされ、現在のプロセスの実行を停止します。 外部出口は exit/2 で呼び出され、Erlangの並行処理の側面で複数のプロセスを処理する必要があります。
- Throw -スローは、プログラマが処理することが期待される場合に使用される例外のクラスです。 終了とエラーと比較して、「クラッシュプロセス」は実際には発生しません。それらの背後にある意図ではなく、フローを制御します。 プログラマがスローを処理することを期待しながらスローを使用する場合、通常はスローを使用するモジュール内でスローを使用することを文書化することをお勧めします。
- 試してみてください… catch *は、成功したケースと発生したエラーを処理しながら式を評価する方法です。
try catch式の一般的な構文は次のとおりです。
構文
try Expression of
SuccessfulPattern1 [Guards] ->
Expression1;
SuccessfulPattern2 [Guards] ->
Expression2
catch
TypeOfError:ExceptionPattern1 ->
Expression3;
TypeOfError:ExceptionPattern2 ->
Expression4
end
*tryとof* の間の式は保護されていると言われます。 これは、その呼び出し内で発生するあらゆる種類の例外がキャッチされることを意味します。 *try ...の間にあるパターンと式 ofおよびcatch* は、* case ...とまったく同じように動作します。 of*.
最後に、キャッチ部分–ここでは、この章で見たそれぞれの型について、 TypeOfError をerror、throw、またはexitに置き換えることができます。 タイプが指定されていない場合、スローが想定されます。
以下は、Erlangのエラーとエラーの理由の一部です-
Error | Type of Error |
---|---|
badarg | Bad argument. The argument is of wrong data type, or is otherwise badly formed. |
badarith | Bad argument in an arithmetic expression. |
\{badmatch,V} | Evaluation of a match expression failed. The value V did not match. |
function_clause | No matching function clause is found when evaluating a function call. |
\{case_clause,V} | No matching branch is found when evaluating a case expression. The value V did not match. |
if_clause | No true branch is found when evaluating an if expression. |
\{try_clause,V} | No matching branch is found when evaluating the of-section of a try expression. The value V did not match. |
undef | The function cannot be found when evaluating a function call.. |
\{badfun,F} | Something is wrong with a fun F |
\{badarity,F} | A fun is applied to the wrong number of arguments. F describes the fun and the arguments. |
timeout_value | The timeout value in a receive..after expression is evaluated to something else than an integer or infinity. |
noproc | Trying to link to a non-existing process. |
以下は、これらの例外がどのように使用され、どのように実行されるかの例です。
- 最初の関数は、考えられるすべてのタイプの例外を生成します。
- 次に、try … catch式で generate_exception を呼び出すラッパー関数を作成します。
例
-module(helloworld).
-compile(export_all).
generate_exception(1) -> a;
generate_exception(2) -> throw(a);
generate_exception(3) -> exit(a);
generate_exception(4) -> {'EXIT', a};
generate_exception(5) -> erlang:error(a).
demo1() ->
[catcher(I) || I <- [1,2,3,4,5]].
catcher(N) ->
try generate_exception(N) of
Val -> {N, normal, Val}
catch
throw:X -> {N, caught, thrown, X};
exit:X -> {N, caught, exited, X};
error:X -> {N, caught, error, X}
end.
demo2() ->
[{I, (catch generate_exception(I))} || I <- [1,2,3,4,5]].
demo3() ->
try generate_exception(5)
catch
error:X ->
{X, erlang:get_stacktrace()}
end.
lookup(N) ->
case(N) of
1 -> {'EXIT', a};
2 -> exit(a)
end.
プログラムをhelloworld:demo()として実行する場合。 、私たちは次の出力を取得します-
出力
[{1,normal,a},
{2,caught,thrown,a},
{3,caught,exited,a},
{4,normal,{'EXIT',a}},
{5,caught,error,a}]
アーラン-マクロ
マクロは通常、インラインコードの置換に使用されます。 Erlangでは、マクロは次のステートメントで定義されます。
- -define(定数、置換)。
- -define(Func(Var1、Var2、..、Var)、Replacement)。
以下は、最初の構文を使用したマクロの例です-
例
-module(helloworld).
-export([start/0]).
-define(a,1).
start() ->
io:fwrite("~w",[?a]).
上記のプログラムから、「?」記号を使用してマクロが展開されることがわかります。 定数は、マクロで定義された値に置き換えられます。
上記のプログラムの出力は次のようになります-
出力
1
関数クラスを使用したマクロの例は次のとおりです-
例
-module(helloworld).
-export([start/0]).
-define(macro1(X,Y),{X+Y}).
start() ->
io:fwrite("~w",[?macro1(1,2)]).
上記のプログラムの出力は次のようになります-
出力
{3}
次の追加ステートメントは、マクロで利用可能です-
- * undef(Macro)*-マクロの定義を解除します。この後、マクロを呼び出すことはできません。
- * ifdef(Macro)*-マクロが定義されている場合にのみ、次の行を評価します。
- * ifndef(Macro)*-Macroが未定義の場合にのみ、次の行を評価します。
- else -ifdefまたはifndefステートメントの後に許可されます。 条件が偽の場合、elseに続くステートメントが評価されます。
- endif -ifdefまたはifndefステートメントの終了をマークします。
上記のステートメントを使用するときは、次のプログラムに示すように適切な方法で使用する必要があります。
-ifdef(<FlagName>).
-define(...).
-else.
-define(...).
-endif.
Erlang-ヘッダーファイル
ヘッダーファイルは、他のプログラミング言語のインクルードファイルに似ています。 モジュールを異なるファイルに分割し、これらのヘッダーファイルに個別のプログラムにアクセスするのに便利です。 ヘッダーファイルの動作を確認するために、以前のレコードの例の1つを見てみましょう。
最初に user.hrl というファイルを作成し、次のコードを追加しましょう-
-record(person, {name = "", id}).
メインプログラムファイルに、次のコードを追加しましょう-
例
-module(helloworld).
-export([start/0]).
-include("user.hrl").
start() ->
P = #person{name = "John",id = 1},
io:fwrite("~p~n",[P#person.id]),
io:fwrite("~p~n",[P#person.name]).
上記のプログラムからわかるように、実際には .record コードを自動的に挿入するuser.hrlファイルが含まれています。
上記のプログラムを実行すると、次の出力が得られます。
出力
1
“John”
マクロで同じことを行うこともできます。ヘッダーファイル内でマクロを定義し、メインファイルで参照することができます。 この例を見てみましょう-
最初に user.hrl というファイルを作成し、次のコードを追加しましょう-
-define(macro1(X,Y),{X+Y}).
メインプログラムファイルに、次のコードを追加しましょう-
例
-module(helloworld).
-export([start/0]).
-include("user.hrl").
start() ->
io:fwrite("~w",[?macro1(1,2)]).
上記のプログラムを実行すると、次の出力が得られます-
出力
{3}
Erlang-プリプロセッサ
Erlangモジュールがコンパイルされる前に、Erlangプリプロセッサによって自動的に処理されます。 プリプロセッサは、ソースファイルにある可能性のあるマクロを展開し、必要なインクルードファイルを挿入します。
通常、プリプロセッサの出力を確認する必要はありませんが、例外的な状況(たとえば、障害のあるマクロのデバッグ時)では、プリプロセッサの出力を保存することをお勧めします。 モジュール some_module.erl の前処理の結果を確認するには、OSシェルコマンドを使用します。
erlc -P some_module.erl
たとえば、次のコードファイルがあったと仮定します-
例
-module(helloworld).
-export([start/0]).
-include("user.hrl").
start() ->
io:fwrite("~w",[?macro1(1,2)]).
そして、コマンドラインから次のコマンドを実行した場合-
erlc –P helloworld.erl
*helloworld.P* というファイルが生成されます。 このファイルを開くと、プリプロセッサがコンパイルする次の内容が見つかります。
-file("helloworld.erl", 1). -module(helloworld).
-export([start/0]).
-file("user.hrl", 1).
-file("helloworld.erl", 3).
start() ->
io:fwrite("~w", [{1 + 2}]).
アーラン-パターンマッチング
パターンは用語と同じように見えます。アトムと数字のような単純なリテラル、タプルとリストのような複合、または両方の混合が可能です。 変数には、大文字またはアンダースコアで始まる英数字の文字列を含めることもできます。 特別な「匿名変数」、_(アンダースコア)は、一致する値を気にせず、使用しない場合に使用されます。
一致する用語と同じ「形状」を持ち、遭遇するアトムが同じ場合、パターンは一致します。 たとえば、次の一致が成功します-
- B = 1。
- 2 = 2。
- \ {ok、C} = \ {ok、40}。
- [H | T] = [1、2、3,4]。
4番目の例では、用語で説明されているように、リストの先頭と末尾を示すパイプ(|)があります。 また、左側はパターンの通常のケースである右側と一致する必要があることに注意してください。
次のパターンマッチングの例は失敗します。
- 1 = 2。
- \ {ok、A} = \ {failure、 "質問を知らない"}。
- [H | T] = []。
パターンマッチング演算子の場合、失敗するとエラーが生成され、プロセスは終了します。 これをトラップして処理する方法については、エラーで説明しています。 パターンを使用して、関数のどの句を実行するかを選択します。
アーラン-ガード
ガードは、パターンマッチングの能力を高めるために使用できる構造です。 ガードを使用すると、パターン内の変数に対して簡単なテストと比較を実行できます。
ガードステートメントの一般的な構文は次のとおりです-
function(parameter) when condition ->
どこで、
- * Function(parameter)*-これは、ガード条件で使用される関数宣言です。
- パラメータ-一般に、ガード条件はパラメータに基づいています。
- 条件-関数を実行する必要があるかどうかを確認するために評価する必要がある条件。
- ガード条件が指定されている場合、whenステートメントを使用する必要があります。
ガードの使用方法の簡単な例を見てみましょう-
例
-module(helloworld).
-export([display/1,start/0]).
display(N) when N > 10 ->
io:fwrite("greater then 10");
display(N) when N < 10 -> io:fwrite("Less
than 10").
start() ->
display(11).
上記の例について、次のことに注意する必要があります-
- 表示機能は、ガードとともに定義されます。 最初の表示宣言には、パラメーターNが10より大きい場合のガードがあります。 したがって、パラメーターが10より大きい場合、その関数が呼び出されます。
- 表示関数が再び定義されますが、今回は10未満のガードで定義されています。 この方法で、同じ関数を複数回定義し、それぞれに個別のガード条件を設定できます。
上記のプログラムの出力は次のようになります-
出力
greater than 10
ガード条件は、 if else および case ステートメントにも使用できます。 これらのステートメントに対してガード操作を実行する方法を見てみましょう。
「if」ステートメントのガード
ガードはifステートメントにも使用できるため、実行される一連のステートメントはガード条件に基づいています。 これを達成する方法を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
N = 9,
if
N > 10 ->
io:fwrite("N is greater than 10");
true ->
io:fwrite("N is less than 10")
end.
上記の例について、次のことに注意する必要があります-
- ガード機能はifステートメントとともに使用されます。 ガード関数がtrueと評価された場合、ステートメント「N is than than 10」が表示されます。
- ガード関数がfalseと評価されると、「N is less than 10」というステートメントが表示されます。
上記のプログラムの出力は次のようになります-
出力
N is less than 10
「ケース」ステートメントの警備員
ガードはcaseステートメントにも使用できるため、実行される一連のステートメントはガード条件に基づいています。 これを達成する方法を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
A = 9,
case A of {A} when A>10 ->
io:fwrite("The value of A is greater than 10"); _ ->
io:fwrite("The value of A is less than 10")
end.
上記の例について、次のことに注意する必要があります-
- ガード関数は、caseステートメントと共に使用されます。 ガード関数がtrueと評価されると、「Aの値は10より大きい」というステートメントが表示されます。
- ガード関数が他の何かに評価される場合、「Aの値は10未満です」というステートメントが表示されます。
上記のプログラムの出力は次のようになります-
出力
The value of A is less than 10
複数のガード条件
関数に対して複数のガード条件を指定することもできます。 複数のガード条件を持つガードステートメントの一般的な構文は次のとおりです-
function(parameter) when condition1 , condition1 , .. conditionN ->
どこで、
- * Function(parameter)*-これは、ガード条件を使用した関数宣言です。
- パラメータ-一般に、ガード条件はパラメータに基づいています。
- condition1、condition1、.. conditionN -これらは、関数に適用される複数のガード条件です。
- ガード条件が指定されている場合、whenステートメントを使用する必要があります。
複数のガードを使用する方法の簡単な例を見てみましょう-
例
-module(helloworld).
-export([display/1,start/0]).
display(N) when N > 10 , is_integer(N) ->
io:fwrite("greater then 10");
display(N) when N < 10 ->
io:fwrite("Less than 10").
start() ->
display(11).
上記の例については、次の点に注意する必要があります-
- 最初の表示関数宣言では、N> 10の条件に加えて、 is_integer の条件も指定されています。 したがって、Nの値が10以上の整数である場合にのみ、この関数が実行されます。
上記のプログラムの出力は次のようになります-
出力
Greater than 10
アーラン-BIFS
BIFは、Erlangに組み込まれている関数です。 彼らは通常、Erlangでプログラムすることが不可能なタスクを実行します。 たとえば、リストをタプルに変換したり、現在の日時を見つけることはできません。 このような操作を実行するには、BIFを呼び出します。
BIFの使用方法の例を見てみましょう-
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~p~n",[tuple_to_list({1,2,3})]),
io:fwrite("~p~n",[time()]).
上記の例について、次のことに注意する必要があります-
- 最初の例では、 tuple_to_list というBIFを使用して、タプルをリストに変換しています。
- 2番目のBIF関数では、* time関数*を使用してシステム時間を出力しています。
上記のプログラムの出力は次のようになります-
出力
[1,2,3]
{10,54,56}
Erlangで利用可能なBIF関数のいくつかを見てみましょう。
Sr.No. | BIF Functions & Description |
---|---|
1 |
このメソッドは、現在のシステム日付を返します。 |
2 |
このメソッドは、ビット文字列に含まれるバイト数を返します。 |
3 |
このメソッドは、タプルのN番目の要素を返します。 |
4 |
このメソッドは、特定の数値の浮動小数点値を返します。 |
5 |
このメソッドは、プロセス辞書をリストとして返します。 |
6 |
このメソッドは、 key、value ペアをプロセス辞書に入れるために使用されます。 |
7 |
このメソッドは、システムのローカル日時を提供するために使用されます。 |
8 |
Erlangエミュレーターによって動的に割り当てられたメモリーに関する情報を含むリストを返します。 |
9 |
このメソッドは、タプル\ {MegaSecs、Secs、MicroSecs}を返します。これは、1970年1月1日00:00 GMTからの経過時間です。 |
10 |
ローカルノード上のすべてのポートのリストを返します |
11 |
ローカルノードに現在存在するすべてのプロセスに対応するプロセス識別子のリストを返します。 |
12 |
協定世界時(UTC)に従って現在の日付と時刻を返します。 |
アーラン-バイナリ
バイナリと呼ばれるデータ構造を使用して、大量の生データを保存します。 バイナリはリストやタプルよりもはるかにスペース効率の良い方法でデータを保存し、ランタイムシステムはバイナリの効率的な入出力のために最適化されています。
バイナリは、整数または文字列のシーケンスとして書き込まれ、出力されます。これらは、かっこで囲まれた二重より小さいおよびより大きい二重で囲まれます。
以下は、Erlangのバイナリの例です-
例
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~p~n",[<<5,10,20>>]),
io:fwrite("~p~n",[<<"hello">>]).
上記のプログラムを実行すると、次の結果が得られます。
出力
<<5,10,20>>
<<"hello">>
バイナリを操作するために利用可能なErlang関数を見てみましょう-
Sr.No. | Methods & Description |
---|---|
1 |
このメソッドは、既存のリストをバイナリのリストに変換するために使用されます。 |
2 |
このメソッドは、指定されたインデックス位置に基づいてバイナリリストを分割するために使用されます。 |
3 |
このメソッドは、用語をバイナリに変換するために使用されます。 |
4 |
このメソッドは、ビット文字列が実際にバイナリ値であるかどうかを確認するために使用されます。 |
5 |
このメソッドは、バイナリ文字列の一部を抽出するために使用されます |
6 |
このメソッドは、バイナリ値を浮動小数点値に変換するために使用されます。 |
7 |
このメソッドは、バイナリ値を整数値に変換するために使用されます。 |
8 |
このメソッドは、バイナリ値をリストに変換するために使用されます。 |
9 |
このメソッドは、バイナリ値をアトムに変換するために使用されます。 |
アーラン-ファン
Funは、Erlangで匿名関数を定義するために使用されます。 匿名関数の一般的な構文は以下のとおりです-
構文
F = fun (Arg1, Arg2, ... ArgN) ->
...
End
どこで
- F -これは、匿名関数に割り当てられた変数名です。
- Arg1、Arg2、… ArgN -これらは、匿名関数に渡される引数です。
次の例は、匿名関数の使用方法を示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
A = fun() -> io:fwrite("Hello") end,
A().
上記のプログラムについて、次のことに注意する必要があります。
- 無名関数は変数Aに割り当てられます。
- 変数A()による匿名関数。
上記のプログラムを実行すると、次の結果が得られます。
“Hello”
無名関数の別の例は次のとおりですが、これはパラメーターを使用する場合です。
-module(helloworld).
-export([start/0]).
start() ->
A = fun(X) ->
io:fwrite("~p~n",[X])
end,
A(5).
上記のプログラムを実行すると、次の結果が得られます。
出力
5
変数を使用する
匿名関数には、匿名関数のスコープ外の変数にアクセスする機能があります。 この例を見てみましょう-
例
-module(helloworld).
-export([start/0]).
start() ->
B = 6,
A = fun(X) ->
io:fwrite("~p~n",[X]),
io:fwrite("~p~n",[B])
end,
A(5).
上記のプログラムについて、次のことに注意する必要があります。
- 変数Bは、無名関数の範囲外です。
- 無名関数は、グローバルスコープで定義された変数に引き続きアクセスできます。
上記のプログラムを実行すると、次の結果が得られます。
出力
5
6
関数内の関数
高階関数の他の最も強力な側面の1つは、関数内で関数を定義できることです。 これを達成する方法の例を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
Adder = fun(X) -> fun(Y) -> io:fwrite("~p~n",[X + Y]) end end,
A = Adder(6),
A(10).
上記のプログラムについて、次のことに注意する必要があります。
- 加算器は、fun(X)として定義される高階関数です。
- 加算関数fun(X)には、別の関数fun(Y)への参照があります。
上記のプログラムを実行すると、次の結果が得られます。
出力
16
アーラン-プロセス
Erlangの並行性の粒度はプロセスです。 プロセスは、他のプロセスと同時に実行され、他のプロセスから独立しているアクティビティ/タスクです。 Erlangのこれらのプロセスは、ほとんどの人が使い慣れているプロセスやスレッドとは異なります。 Erlangプロセスは軽量で、他のプロセスから(メモリ)分離で動作し、Erlangの仮想マシン(VM)によってスケジュールされます。 プロセスの作成時間は非常に短く、生成されたばかりのプロセスのメモリフットプリントは非常に小さく、1つのErlang VMで何百万ものプロセスを実行できます。
プロセスは、spawnメソッドの助けを借りて作成されます。 メソッドの一般的な構文は次のとおりです。
構文
spawn(Module, Name, Args)
パラメーター
- モジュール-これは事前定義されたアトム値で、?MODULEでなければなりません。
- 名前-これは、プロセスが定義されたときに呼び出される関数の名前です。
- 引数-これらは、関数に送信する必要がある引数です。
戻り値
作成された新しいプロセスのプロセスIDを返します。
例えば
spawnメソッドの例を次のプログラムに示します。
-module(helloworld).
-export([start/0, call/2]).
call(Arg1, Arg2) ->
io:format("~p ~p~n", [Arg1, Arg2]).
start() ->
Pid = spawn(?MODULE, call, ["hello", "process"]),
io:fwrite("~p",[Pid]).
上記のプログラムについて、次のことに注意する必要があります。
- callという関数が定義されており、プロセスの作成に使用されます。
- spawnメソッドは、パラメーターhelloおよびprocessを使用して呼び出し関数を呼び出します。
出力
上記のプログラムを実行すると、次の結果が得られます。
<0.29.0>"hello" "process"
次に、プロセスで利用可能な他の機能を見てみましょう。
Sr.No. | Methods & Description |
---|---|
1 |
このメソッドは、プロセスIDが存在するかどうかを判断するために使用されます。 |
2 |
これはis_process_alive(Pid)と呼ばれます。 Pidは、ローカルノードのプロセスを参照する必要があります。 |
3 |
プロセスIDをリストに変換します。 |
4 |
登録されているすべてのプロセスの名前のリストを返します。 |
5 |
最もよく使用されるBIFの1つで、呼び出しプロセスのpidを返します。 |
6 |
これは、システムにプロセスを登録するために使用されます。 |
7 |
whereis(Name)と呼ばれます。 名前で登録されているプロセスのpidを返します。 |
8 |
これは、システムでプロセスを登録解除するために使用されます。 |
アーラン-メール
Erlangを使用してメールを送信するには、同じために github から入手可能なパッケージを使用する必要があります。 githubリンクは-https://github.com/Vagabond/gen_smtpです
このリンクには、Erlangアプリケーションから電子メールを送信するために使用できる* smtpユーティリティ*が含まれています。 次の手順に従って、Erlangからメールを送信します。
ステップ1 *- githubサイト*から* erlファイル*をダウンロードします。 ファイルは、 helloworld.erl アプリケーションが存在するディレクトリにダウンロードする必要があります。
ステップ2 *- erlcコマンド*を使用して、以下のリストに示されているすべての* smtp関連ファイル*をコンパイルします。 次のファイルをコンパイルする必要があります。
- smtp_util
- gen_smtp_client
- gen_smtp_server
- gen_smtp_server_session
- ビンスト
- gen_smtp_application
- ソケット
- ステップ3 *-smtpを使用して電子メールを送信するには、次のコードを記述できます。
例
-module(helloworld).
-export([start/0]).
start() ->
gen_smtp_client:send({"[email protected]", ["[email protected]"], "Subject: testing"},
[{relay, "smtp.gmail.com"}, {ssl, true}, {username, "[email protected]"},
{password, "senderpassword"}]).
上記のプログラムについて、次のことに注意する必要があります
- 上記のsmtp関数は、googleから入手可能なsmtpサーバーとともに使用されています。
- 安全なsmtpを使用して送信したいので、sslパラメーターをtrueに指定します。
- リレーを smtp.gmail.com として指定する必要があります。
- 電子メールを送信するためのアクセス権を持つユーザー名とパスワードを記載する必要があります。
上記のすべての設定を構成してプログラムを実行すると、受信者は電子メールを正常に受信します。
Erlang-データベース
Erlangには、SQL ServerやOracleなどの従来のデータベースに接続する機能があります。 Erlangには、データベースの操作に使用できる*組み込みodbcライブラリ*があります。
データベース接続
この例では、Microsoft SQL Serverを使用します。 Microsoft SQL Serverデータベースに接続する前に、次のポインターがチェックされていることを確認してください。
- データベースTESTDBを作成しました。
- TESTDBにテーブルEMPLOYEEを作成しました。
- このテーブルには、FIRST_NAME、LAST_NAME、AGE、SEX、およびINCOMEフィールドがあります。
- ユーザーID「testuser」とパスワード「test123」は、TESTDBにアクセスするように設定されています。
- データベースへのODBC接続を作成する usersqlserver という名前のODBC DSNを作成したことを確認します
接続の確立
データベースへの接続を確立するには、次のコード例を使用できます。
例
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver;UID = testuser;PWD = test123", []),
io:fwrite("~p",[Ref]).
上記のプログラムの出力は次のとおりです-
出力
<0.33.0>
上記のプログラムについて、次のことに注意する必要があります。
- odbcライブラリのstartメソッドは、データベース操作の開始を示すために使用されます。
- 接続方法では、接続するためにDSN、ユーザー名、およびパスワードが必要です。
データベーステーブルの作成
データベースに接続した後の次のステップは、データベースにテーブルを作成することです。 次の例は、Erlangを使用してデータベースにテーブルを作成する方法を示しています。
例
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123, []),
odbc:sql_query(Ref, "CREATE TABLE EMPLOYEE (FIRSTNAME char varying(20),
LASTNAME char varying(20), AGE integer, SEX char(1), INCOME integer)")
データベースを確認すると、 EMPLOYEE というテーブルが作成されていることがわかります。
データベースへのレコードの挿入
データベーステーブルにレコードを作成する場合に必要です。
次の例は、従業員テーブルにレコードを挿入します。 テーブルが正常に更新されると、レコードとステートメントは更新されたレコードの値と更新されたレコードの数を返します。
例
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[odbc:sql_query(Ref,
"INSERT INTO EMPLOYEE VALUES('Mac', 'Mohan', 20, 'M', 2000)")]).
上記のプログラムの出力は次のようになります-
出力
{updated,1}
データベースからのレコードの取得
Erlangには、データベースからレコードをフェッチする機能もあります。 これは* sql_queryメソッド*を介して行われます。
例は、次のプログラムに示されています-
- 例 *
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[odbc:sql_query(Ref, "SELECT* FROM EMPLOYEE") ]).
上記のプログラムの出力は次のようになります-
出力
{selected,["FIRSTNAME","LASTNAME","AGE","SEX","INCOME"],
[{"Mac","Mohan",20,"M",2000}]}
したがって、最後のセクションの挿入コマンドが機能し、選択コマンドが正しいデータを返したことを確認できます。
パラメータに基づいてデータベースからレコードを取得する
Erlangには、特定のフィルター条件に基づいてデータベースからレコードをフェッチする機能もあります。
例は次のとおりです-
- 例 *
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN=usersqlserver; UID=testuser;PWD=test123", []),
io:fwrite("~p",[ odbc:param_query(Ref, "SELECT* FROM EMPLOYEE WHERE SEX=?",
[{{sql_char, 1}, ["M"]}])]).
上記のプログラムの出力は次のようになります-
出力
{selected,["FIRSTNAME","LASTNAME","AGE","SEX","INCOME"],
[{"Mac","Mohan",20,"M",2000}]}
データベースからのレコードの更新
Erlangには、データベースからレコードを更新する機能もあります。
同じ例は次のとおりです-
例
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[ odbc:sql_query(Ref, "
UPDATE EMPLOYEE SET AGE = 5 WHERE INCOME= 2000")]).
上記のプログラムの出力は次のようになります-
出力
{updated,1}
データベースからレコードを削除する
Erlangには、データベースからレコードを削除する機能もあります。
同じ例は次のとおりです-
例
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[ odbc:sql_query(Ref, "DELETE EMPLOYEE WHERE INCOME= 2000")]).
上記のプログラムの出力は次のようになります-
出力
{updated,1}
テーブル構造
Erlangには、テーブル構造を記述する機能もあります。
例は次のとおりです-
例
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[odbc:describe_table(Ref, "EMPLOYEE")]).
上記のプログラムの出力は次のようになります-
出力
{ok,[{"FIRSTNAME",{sql_varchar,20}},
{"LASTNAME",{sql_varchar,20}},
{"AGE",sql_integer},
{"SEX",{sql_char,1}},
{"INCOME",sql_integer}]}
レコード数
Erlangには、テーブル内のレコードの総数を取得する機能もあります。
同じ例が次のプログラムに示されています。
- 例 *
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = sa;PWD = demo123", []),
io:fwrite("~p",[odbc:select_count(Ref, "SELECT* FROM EMPLOYEE")]).
上記のプログラムの出力は次のようになります-
{ok,1}
アーラン-ポート
Erlangでは、ポートは異なるプログラム間の通信に使用されます。 ソケットは、マシンがインターネットプロトコル(IP)を使用してインターネット経由で通信できるようにする通信エンドポイントです。
ポートで使用されるプロトコルの種類
通信に使用できるプロトコルには2つのタイプがあります。 1つはUDPで、もう1つはTCPです。 UDPを使用すると、アプリケーションは互いに短いメッセージ(データグラムと呼ばれる)を送信できますが、これらのメッセージの配信は保証されません。 また、順不同で到着することもあります。 一方、TCPは、接続が確立されている限り順番に配信される信頼性の高いバイトストリームを提供します。
UDPを使用してポートを開く簡単な例を見てみましょう。
例
-module(helloworld).
-export([start/0]).
start() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p",[Socket]).
上記のプログラムについて、次のことに注意する必要があります
- gen_udp には、UDP通信に使用されるErlangのモジュールが含まれています。
- ここで8789は、Erlangで開かれているポート番号です。 このポート番号が使用可能であり、使用できることを確認する必要があります。
上記のプログラムの出力は-
#Port<0.376>
ポートでメッセージを送信する
ポートが開かれると、ポートでメッセージを送信できます。 これは、sendメソッドを介して行われます。 構文と次の例を見てみましょう。
構文
send(Socket, Address, Port, Packet)
パラメーター
- ソケット-これはgen_udp:openコマンドで作成されたソケットです。
- アドレス-これは、メッセージの送信先のマシンアドレスです。
- ポート-これは、メッセージを送信する必要があるポート番号です。
- パケット-これは、送信する必要があるパケットまたはメッセージの詳細です。
戻り値
メッセージが適切に送信された場合、okメッセージが返されます。
例えば
-module(helloworld).
-export([start/0]).
start() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p",[Socket]),
io:fwrite("~p",[gen_udp:send
(Socket,"localhost",8789,"Hello")]).
出力
上記のプログラムの出力は次のようになります。
#Port<0.376>ok
ポートでメッセージを受信する
ポートを開くと、ポートでメッセージを受信することもできます。 これは* recvメソッド*を介して行われます。 構文と次の例を見てみましょう。
構文
recv(Socket, length)
パラメーター
- ソケット-これはgen_udp:openコマンドで作成されたソケットです。
- 長さ-これは受信する必要があるメッセージの長さです。
戻り値
メッセージが適切に送信された場合、okメッセージが返されます。
例えば
-module(helloworld).
-export([start/0]).
start() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p",[Socket]),
io:fwrite("~p",[gen_udp:send(Socket,"localhost",8789,"Hello")]),
io:fwrite("~p",[gen_udp:recv(Socket, 20)]).
完全なプログラム
明らかに、同じプログラムで同じ送受信メッセージを使用することはできません。 異なるプログラムで定義する必要があります。 したがって、メッセージをリッスンするサーバーコンポーネントとメッセージを送信するクライアントコンポーネントを作成する次のコードを作成しましょう。
例
-module(helloworld).
-export([start/0,client/1]).
start() ->
spawn(fun() -> server(4000) end).
server(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary, {active, false}]),
io:format("server opened socket:~p~n",[Socket]),
loop(Socket).
loop(Socket) ->
inet:setopts(Socket, [{active, once}]),
receive
{udp, Socket, Host, Port, Bin} ->
io:format("server received:~p~n",[Bin]),
gen_udp:send(Socket, Host, Port, Bin),
loop(Socket)
end.
client(N) ->
{ok, Socket} = gen_udp:open(0, [binary]),
io:format("client opened socket=~p~n",[Socket]),
ok = gen_udp:send(Socket, "localhost", 4000, N), Value = receive
{udp, Socket, _, _, Bin} ->
io:format("client received:~p~n",[Bin]) after 2000 ->
0
end,
gen_udp:close(Socket),
Value.
上記のプログラムについて、次のことに注意する必要があります。
- 2つの関数を定義します。最初の関数はサーバーです。 これは、ポート4000でリッスンするために使用されます。 2番目は、サーバーコンポーネントにメッセージ「Hello」を送信するために使用されるクライアントです。
- 受信ループは、定義ループ内で送信されたメッセージを読み取るために使用されます。
出力
次に、2つのウィンドウからプログラムを実行する必要があります。 最初のウィンドウは、* erlコマンドラインウィンドウ*で次のコードを実行することにより、サーバーコンポーネントを実行するために使用されます。
helloworld:start().
これにより、コマンドラインウィンドウに次の出力が表示されます。
server opened socket:#Port<0.2314>
次に、2番目のerlコマンドラインウィンドウで、次のコマンドを実行します。
Helloworld:client(“<<Hello>>”).
このコマンドを発行すると、最初のコマンドラインウィンドウに次の出力が表示されます。
server received:<<"Hello">>
Erlang-分散プログラミング
分散プログラムは、コンピューターのネットワーク上で実行するように設計されたプログラムであり、メッセージの受け渡しによってのみ活動を調整できます。
分散アプリケーションを作成する理由はいくつかあります。 ここにそれらのいくつかがあります。
- パフォーマンス-プログラムの異なる部分が異なるマシンで並行して実行されるようにすることで、プログラムを高速化できます。
- 信頼性-システムを複数のマシンで実行するように構成することにより、フォールトトレラントシステムを作成できます。 1台のマシンに障害が発生した場合、別のマシンで続行できます。
- スケーラビリティ-アプリケーションをスケールアップすると、遅かれ早かれ、最も強力なマシンでさえ機能を使い果たします。 この段階では、マシンを追加して容量を追加する必要があります。 新しいマシンの追加は、アプリケーションアーキテクチャを大幅に変更する必要のない単純な操作である必要があります。
分散Erlangの中心概念はノードです。 ノードは自己完結型です。
Erlangシステムには、独自のアドレス空間と独自のプロセスセットを備えた完全な仮想マシンが含まれています。
*Distributed Programming* に使用されるさまざまな*メソッド*を見てみましょう。
Sr.No. | Methods & Description |
---|---|
1 |
これは、新しいプロセスを作成して初期化するために使用されます。 |
2 |
これは、プロセスを実行する必要があるノードの値を決定するために使用されます。 |
3 |
これは、ノードで新しいプロセスを作成するために使用されます。 |
4 |
これは、ローカルノードが動作しており、分散システムの一部である場合にtrueを返します。 |
5 |
これは、ノードに新しいプロセスリンクを作成するために使用されます。 |
アーラン-OTP
OTPはOpen Telecom Platformの略です。 これは、アプリケーションのオペレーティングシステムであり、大規模でフォールトトレラントな分散アプリケーションの構築に使用される一連のライブラリと手順です。 OTPを使用して独自のアプリケーションをプログラミングする場合、非常に役立つ中心的な概念はOTPの動作です。 動作は、一般的な動作パターンをカプセル化します。コールバックモジュールによってパラメーター化されるアプリケーションフレームワークと考えてください。
OTPの能力は、フォールトトレランス、スケーラビリティ、動的コードのアップグレードなどのプロパティにあり、動作自体によって提供できます。 最初の基本概念は、OTP環境の基本を模倣するサーバーコンポーネントを作成することです。同じための次の例を見てみましょう。
例
-module(server).
-export([start/2, rpc/2]).
start(Name, Mod) ->
register(Name, spawn(fun() -> loop(Name, Mod, Mod:init()) end)).
rpc(Name, Request) ->
Name ! {self(), Request},
receive
{Name, Response} -> Response
end.
loop(Name, Mod, State) ->
receive
{From, Request} ->
{Response, State1} = Mod:handle(Request, State),
From ! {Name, Response},
loop(Name, Mod, State1)
end.
上記のプログラムについては、次のことに注意する必要があります-
- 登録機能を使用してシステムに登録された場合のプロセス。
- プロセスは、処理を処理するループ関数を生成します。
それでは、サーバープログラムを利用するクライアントプログラムを作成しましょう。
例
-module(name_server).
-export([init/0, add/2, whereis/1, handle/2]).
-import(server1, [rpc/2]).
add(Name, Place) -> rpc(name_server, {add, Name, Place}).
whereis(Name) -> rpc(name_server, {whereis, Name}).
init() -> dict:new().
handle({add, Name, Place}, Dict) -> {ok, dict:store(Name, Place, Dict)};
handle({whereis, Name}, Dict) -> {dict:find(Name, Dict), Dict}.
このコードは実際に2つのタスクを実行します。 サーバーフレームワークコードから呼び出されるコールバックモジュールとして機能すると同時に、クライアントによって呼び出されるインターフェイスルーチンが含まれています。 通常のOTP規則では、同じモジュールで両方の機能を組み合わせます。
だからここに上記のプログラムを実行する必要がある方法です-
*erl* では、まず次のコマンドを実行してサーバープログラムを実行します。
server(name_server,name_server)
あなたは次の出力を取得します-
出力
true
次に、次のコマンドを実行します
name_server.add(erlang,”finddevguides”).
あなたは次の出力を取得します-
出力
Ok
次に、次のコマンドを実行します-
name_server.whereis(erlang).
あなたは次の出力を取得します-
出力
{ok,"finddevguides"}
アーラン-並行性
Erlangでの並行プログラミングには、次の基本原則またはプロセスが必要です。
リストには、次の原則が含まれています-
piD = spawn(楽しい)
Funを評価する新しい並行プロセスを作成します。 新しいプロセスは、呼び出し元と並行して実行されます。 例は次のとおりです-
例
-module(helloworld).
-export([start/0]).
start() ->
spawn(fun() -> server("Hello") end).
server(Message) ->
io:fwrite("~p",[Message]).
上記のプログラムの出力は-
出力
“Hello”
Pid! メッセージ
識別子Pidでメッセージをプロセスに送信します。 メッセージ送信は非同期です。 送信者は待たずに、実行していた処理を続行します。 ’!’ は送信演算子と呼ばれます。
例は次のとおりです-
例
-module(helloworld).
-export([start/0]).
start() ->
Pid = spawn(fun() -> server("Hello") end),
Pid ! {hello}.
server(Message) ->
io:fwrite("~p",[Message]).
受信…終了
プロセスに送信されたメッセージを受信します。 次の構文があります-
構文
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
End
メッセージがプロセスに到着すると、システムはPattern1(ガードGuard1を使用可能)と照合しようとします。これが成功すると、Expressions1を評価します。 最初のパターンが一致しない場合、Pattern2などを試行します。 一致するパターンがない場合、メッセージは後の処理のために保存され、プロセスは次のメッセージを待ちます。
3つのコマンドすべてを含むプロセス全体の例を次のプログラムに示します。
例
-module(helloworld).
-export([loop/0,start/0]).
loop() ->
receive
{rectangle, Width, Ht} ->
io:fwrite("Area of rectangle is ~p~n" ,[Width *Ht]),
loop();
{circle, R} ->
io:fwrite("Area of circle is ~p~n" , [3.14159* R * R]),
loop();
Other ->
io:fwrite("Unknown"),
loop()
end.
start() ->
Pid = spawn(fun() -> loop() end),
Pid ! {rectangle, 6, 10}.
上記のプログラムについては、次のことに注意する必要があります-
- ループ機能には受信終了ループがあります。 そのため、メッセージが送信されると、受信終了ループによって処理されます。
- ループ関数に進む新しいプロセスが生成されます。 *メッセージは、Pidを介して生成されたプロセスに送信されます! メッセージコマンド。
上記のプログラムの出力は-
出力
Area of the Rectangle is 60
プロセスの最大数
並行処理では、システムで許可されるプロセスの最大数を決定することが重要です。 そうすれば、システム上で同時に実行できるプロセスの数を理解できるはずです。
システムで実行できるプロセスの最大数を決定する方法の例を見てみましょう。
-module(helloworld).
-export([max/1,start/0]).
max(N) ->
Max = erlang:system_info(process_limit),
io:format("Maximum allowed processes:~p~n" ,[Max]),
statistics(runtime),
statistics(wall_clock),
L = for(1, N, fun() -> spawn(fun() -> wait() end) end),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock), lists:foreach(fun(Pid) -> Pid ! die end, L),
U1 = Time1* 1000/N,
U2 = Time2 * 1000/N,
io:format("Process spawn time=~p (~p) microseconds~n" , [U1, U2]).
wait() ->
receive
die -> void
end.
for(N, N, F) -> [F()];
for(I, N, F) -> [F()|for(I+1, N, F)].
start()->
max(1000),
max(100000).
優れた処理能力を備えたマシンでは、上記の両方のmax関数がパスします。 以下は、上記のプログラムのサンプル出力です。
Maximum allowed processes:262144
Process spawn time=47.0 (16.0) microseconds
Maximum allowed processes:262144
Process spawn time=12.81 (10.15) microseconds
タイムアウトで受信
時々、受信ステートメントは、決して来ないメッセージを永遠に待つかもしれません。 これにはいくつかの理由が考えられます。 たとえば、プログラムに論理エラーがあるか、メッセージを送信しようとしていたプロセスがメッセージを送信する前にクラッシュした可能性があります。 この問題を回避するために、受信ステートメントにタイムアウトを追加できます。 これは、プロセスがメッセージの受信を待機する最大時間を設定します。
以下は、タイムアウトが指定された受信メッセージの構文です。
構文
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
after Time ->
Expressions
end
最も簡単な例は、次のプログラムに示すように、スリーパー関数を作成することです。
例
-module(helloworld).
-export([sleep/1,start/0]).
sleep(T) ->
receive
after T ->
true
end.
start()->
sleep(1000).
上記のコードは、実際に終了する前に1000ミリ秒間スリープします。
選択的受信
Erlangの各プロセスには、関連付けられたメールボックスがあります。 プロセスにメッセージを送信すると、メッセージはメールボックスに入れられます。 このメールボックスが検査されるのは、プログラムが受信ステートメントを評価するときだけです。
以下は、選択的受信ステートメントの一般的な構文です。
構文
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard1] ->
Expressions1;
...
after
Time ->
ExpressionTimeout
end
これは、上記の受信ステートメントの仕組みです-
- receiveステートメントを入力すると、タイマーが開始されます(ただし、式にafterセクションが存在する場合のみ)。
- メールボックスの最初のメッセージを取得し、Pattern1、Pattern2などと照合します。 一致が成功すると、メッセージはメールボックスから削除され、パターンに続く式が評価されます。
- receiveステートメントのパターンがメールボックスの最初のメッセージと一致しない場合、最初のメッセージはメールボックスから削除され、「保存キュー」に入れられます。次に、メールボックスの2番目のメッセージが試行されます。 この手順は、一致するメッセージが見つかるか、メールボックス内のすべてのメッセージが検査されるまで繰り返されます。
- メールボックス内のメッセージがどれも一致しない場合、プロセスは中断され、新しいメッセージがメールボックスに次に配置されるときに実行のために再スケジュールされます。 新しいメッセージが到着しても、保存キュー内のメッセージは再照合されないことに注意してください。新しいメッセージのみが一致します。
- メッセージが一致するとすぐに、保存キューに入れられたすべてのメッセージは、プロセスに到着した順序でメールボックスに再入力されます。 タイマーが設定されている場合、クリアされます。
- メッセージを待っているときにタイマーが経過した場合は、ExpressionsTimeout式を評価し、保存されたメッセージをプロセスに到着した順にメールボックスに戻します。
アーラン-パフォーマンス
パフォーマンスについて話すときは、Erlangについて次の点に注意する必要があります。
- ファンは非常に高速です-ファンはR6Bで独自のデータ型を与えられ、R7Bでさらに最適化されました。
- * 演算子の使用*-この演算子は適切な方法で使用する必要があります。 次の例は、操作を行う間違った方法です。
例
-module(helloworld).
-export([start/0]).
start()->
fun_reverse([H|T]) ->
fun_reverse(T)++[H];
fun_reverse([]) ->
[].
++演算子が左のオペランドをコピーすると、結果が繰り返しコピーされ、2次の複雑さが生じます。
- 文字列の使用-文字列の処理が不適切な場合、処理が遅くなる可能性があります。 Erlangでは、文字列の使用方法についてもう少し考え、適切な表現を選択する必要があります。 正規表現を使用する場合は、 obsolete regexp module の代わりにSTDLIBのre-moduleを使用してください。
- * BEAMはスタックベースのバイトコード仮想マシン*-BEAMはレジスタベースの仮想マシンです。 一時的な値を保持し、関数を呼び出すときに引数を渡すために使用される1024個の仮想レジスタがあります。 関数呼び出しを生き残るために必要な変数はスタックに保存されます。 BEAMはスレッドコードインタープリターです。 各命令は、実行可能なCコードを直接指すワードであるため、命令のディスパッチが非常に高速になります。
Erlang-ドライバー
Erlangランタイムシステム内で外国語プログラムを実行したい場合があります。 この場合、プログラムは共有ライブラリとして記述され、Erlangランタイムシステムに動的にリンクされます。 リンクインドライバーは、プログラマーにはポートプログラムとして認識され、ポートプログラムとまったく同じプロトコルに従います。
ドライバーを作成する
リンクインドライバーを作成することは、外国語コードをErlangとインターフェイスさせる最も効率的な方法ですが、最も危険でもあります。 リンクインドライバーで致命的なエラーが発生すると、Erlangシステムがクラッシュします。
以下は、Erlangでのドライバー実装の例です-
例
-module(helloworld).
-export([start/0, stop/0]).
-export([twice/1, sum/2]).
start() ->
start("example1_drv" ).
start(SharedLib) ->
case erl_ddll:load_driver("." , SharedLib) of
ok -> ok;
{error, already_loaded} -> ok;
_ -> exit({error, could_not_load_driver})
end,
spawn(fun() -> init(SharedLib) end).
init(SharedLib) ->
register(example1_lid, self()),
Port = open_port({spawn, SharedLib}, []),
loop(Port).
stop() ->
example1_lid ! stop.
twice(X) -> call_port({twice, X}).
sum(X,Y) -> call_port({sum, X, Y}). call_port(Msg) ->
example1_lid ! {call, self(), Msg}, receive
{example1_lid, Result} ->
Result
end.
LINKED-IN DRIVERS 223
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}}, receive
{Port, {data, Data}} ->
Caller ! {example1_lid, decode(Data)}
end,
loop(Port);
stop -> Port !
{self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
io:format("~p ~n" , [Reason]),
exit(port_terminated)
end.
encode({twice, X}) -> [1, X];
encode({sum, X, Y}) -> [2, X, Y]. decode([Int]) -> Int.
ドライバーでの作業は非常に複雑であり、ドライバーでの作業には注意が必要です。
Erlang-Webプログラミング
Erlangでは、ErlangでWebサーバーを構築するために* inetsライブラリ*を使用できます。 ErlangでWebプログラミングに使用できる機能のいくつかを見てみましょう。 HTTP要求を処理するためにhttpdとも呼ばれるHTTPサーバーを実装できます。
サーバーは、次のような多数の機能を実装します-
- Secure Sockets Layer(SSL)
- Erlangスクリプトインターフェイス(ESI)
- 共通ゲートウェイインターフェイス(CGI)
- ユーザー認証(Mnesia、Dets、またはプレーンテキストデータベースを使用)
- 共通ログファイル形式(disk_log(3)サポートの有無にかかわらず)
- URLエイリアシング
- アクションマッピング
- ディレクトリ一覧
最初のジョブは、コマンドを使用してWebライブラリを起動することです。
inets:start()
次のステップは、Webサーバーを実装できるように、inetsライブラリの開始機能を実装することです。
以下は、ErlangでWebサーバープロセスを作成する例です。
例えば
-module(helloworld).
-export([start/0]).
start() ->
inets:start(),
Pid = inets:start(httpd, [{port, 8081}, {server_name,"httpd_test"},
{server_root,"D://tmp"},{document_root,"D://tmp/htdocs"},
{bind_address, "localhost"}]), io:fwrite("~p",[Pid]).
上記のプログラムについて、以下の点に注意する必要があります。
*ポート番号は一意であり、他のプログラムで使用されていない必要があります。* httpdサービス*はこのポート番号で開始されます。
* *server_root* および *document_root* は必須パラメーターです。
出力
上記のプログラムの出力は次のとおりです。
{ok,<0.42.0>}
Erlangで* Hello world Webサーバー*を実装するには、次の手順を実行します-
- ステップ1 *-次のコードを実装します-
-module(helloworld).
-export([start/0,service/3]).
start() ->
inets:start(httpd, [
{modules, [
mod_alias,
mod_auth,
mod_esi,
mod_actions,
mod_cgi,
mod_dir,
mod_get,
mod_head,
mod_log,
mod_disk_log
]},
{port,8081},
{server_name,"helloworld"},
{server_root,"D://tmp"},
{document_root,"D://tmp/htdocs"},
{erl_script_alias, {"/erl", [helloworld]}},
{error_log, "error.log"},
{security_log, "security.log"},
{transfer_log, "transfer.log"},
{mime_types,[
{"html","text/html"}, {"css","text/css"}, {"js","application/x-javascript"} ]}
]).
service(SessionID, _Env, _Input) -> mod_esi:deliver(SessionID, [
"Content-Type: text/html\r\n\r\n", "<html><body>Hello, World!</body></html>" ]).
ステップ2 *-次のようにコードを実行します。 上記のファイルをコンパイルしてから、 *erl で次のコマンドを実行します。
c(helloworld).
次の出力が得られます。
{ok,helloworld}
次のコマンドは-
inets:start().
次の出力が得られます。
ok
次のコマンドは-
helloworld:start().
次の出力が得られます。
{ok,<0.50.0>}
ステップ3 *-URL- *http://localhost:8081/erl/hello_world:service にアクセスできるようになりました。