Elixir入門 22: Erlangライブラリ
gumi TECH
Posted on February 19, 2019
本稿はElixir公式サイトの許諾を得て「Erlang libraries」の解説にもとづき、加筆補正を加えて、Elixirで使えるErlangライブラリついてご説明します。
ElixirはErlangのライブラリが使えます。Erlangライブラリを単にラップするのでなく、Erlangのコードへの直接のインタフェースが備わっているのです。Elixirにはない、よく使われて便利なErlangの機能を採り上げてご紹介します。さらに詳しくはErlang「STDLIB Reference Manual」をご参照ください。
binaryモジュール
Elixir組み込みのString
モジュールは、UTF-8でエンコードされたバイナリを扱います。Erlangのbinary
モジュールは、必ずしもUTF-8エンコーディングでないバイナリを使うときに便利です。String.to_charlist/1
はUnicodeのコードポイントを返します。:binary.bin_to_list/1
が返すのは生のバイトデータです。
iex> String.to_charlist("π")
[960]
iex> :binary.bin_to_list("π")
[207, 128]
出力のフォーマット
Elixirには、Cなどの言語にあるprintf
に当たる関数が備わっていません。けれども、Erlang標準ライブラリの関数:io.format/2
と:io_lib.format/2
が使えます。フォーマットは前者が端末出力、後者はiolistです。書式の定め方はprintf
とは異なります。詳しくは:io.format/1
の説明をご参照ください。
iex> :io.format("Pi is approximately given by:~10.3f~n", [:math.pi])
Pi is approximately given by: 3.142
:ok
iex> to_string :io_lib.format("Pi is approximately given by:~10.3f~n", [:math.pi])
"Pi is approximately given by: 3.142\n"
なお、Erlangのフォーマット関数を使うとき、Unicodeの扱いには注意しなければなりません。
iex> :io.format("円周率πは約~10.3f~n", [:math.pi])
åå¨çÏã¯ç´
3.142
:ok
iex> to_string :io_lib.format("円周率πは約:~10.3f~n", [:math.pi])
<<195, 165, 194, 134, 194, 134, 195, 165, 194, 145, 194, 168, 195, 167, 194,
142, 194, 135, 195, 143, 194, 128, 195, 163, 194, 129, 194, 175, 195, 167,
194, 180, 194, 132, 58, 32, 32, 32, 32, 32, 51, 46, 49, 52, 50, 10>>
cryptoモジュール
crypto
モジュールには、ハッシュ関数やデジタル署名あるいは暗号化などの機能が含まれています。crypto.hash/2
は、第2引数のデータから第1引数のハッシュ関数にもとづいてメッセージダイジェストを求めます(「SHA-256」参照)。また、Base.encode16/2
は、バイナリ文字列をbase 16にエンコードする関数です。
iex> Base.encode16(:crypto.hash(:sha256, "Elixir"))
"3315715A7A3AD57428298676C5AE465DADA38D951BDFAC9348A8A31E9C7401CB"
crypto
モジュールは、Erlang標準ライブラリには含まれていません。けれど、Erlangには同梱されています。つまり、使うときにプロジェクトのアプリケーションリストに含めなければなりません。そのためには、mix.exs
のapplication
につぎのように書き加えてください(「Project compilation」参照)。
def application do
[extra_applications: [:crypto]]
end
digraphモジュール
digraph
モジュール(およびdigraph_utils)には、頂点と線分で組み立てられる有向グラフ(directed graph)を扱う関数が備わっています。グラフをつくったあと、モジュールのアルゴリズムを用いて、たとえば2頂点またはループ内の最短経路を見つけることができます。
iex> digraph = :digraph.new()
{:digraph, #Reference<0.2617837314.593887233.57913>,
#Reference<0.2617837314.593887233.57914>,
#Reference<0.2617837314.593887233.57915>, true}
iex> coords = [{0.0, 0.0}, {3.0, 0.0}, {3.0, 4.0}]
[{0.0, 0.0}, {3.0, 0.0}, {3.0, 4.0}]
iex> [v0, v1, v2] = (for c <- coords, do: :digraph.add_vertex(digraph, c))
[{0.0, 0.0}, {3.0, 0.0}, {3.0, 4.0}]
iex> :digraph.add_edge(digraph, v0, v1)
[:"$e" | 0]
iex> :digraph.add_edge(digraph, v1, v2)
[:"$e" | 1]
iex> :digraph.add_edge(digraph, v0, v2)
[:"$e" | 2]
iex> :digraph.get_short_path(digraph, v0, v2)
[{0.0, 0.0}, {3.0, 4.0}]
-
:digraph.new/0
: 空の有向グラフをつくって返します。 -
:digraph.add_vertex/2
: 第1引数のグラフに第2引数の頂点が加わります。 -
:digraph.add_edge/3
: 第1引数のグラフに第2および第3引数を結ぶ線が加えられます。 -
:digraph.get_short_path/3
: 第1引数のグラフの中で、第2引数の頂点から第3引数の頂点に至る最短経路をリストで返します。
Erlangタームストレージ(ETS)
モジュールets
とdets
は、大量のデータ構造を扱ってメモリやディスクに格納します。
ETSを使うと、タプルの含まれたテーブルがつくれます。デフォルトでは、ETSのテーブルは保護されています。つまり、所有者だけがテーブルに書き込めるということです。他のプロセスは読み取りのみできます。ETSに備わる機能は、シンプルなデータベースやキーと値の保管、あるいはキャッシュの仕組みなどに使えるでしょう。
ets
モジュールの関数は、副作用としてテーブルの状態を変更します。
iex> table = :ets.new(:ets_test, [])
#Reference<0.2617837314.593887233.58208>
iex> :ets.insert(table, {"China", 1_390_080_000})
true
iex> :ets.insert(table, {"USA", 325_890_000})
true
iex> :ets.insert(table, {"Japan", 126_750_000})
true
iex> :ets.i(table)
<1 > {<<"USA">>,325890000}
<2 > {<<"China">>,1390080000}
<3 > {<<"Japan">>,126750000}
EOT (q)uit (p)Digits (k)ill /Regexp -->
-
:ets.new/2
: テーブルをつくって、参照のためのテーブルIDが返されます。引数は名前とオプションのリストです。 -
:ets.insert/2
: テーブルにオブジェクトを加えます。 -
:ets.i/1
: 端末でテーブルを閲覧します。
待ち状態を終了するには、[q]キーと[enter]を入力してください。
EOT (q)uit (p)Digits (k)ill /Regexp -->q
:ok
mathモジュール
math
モジュールは、三角関数や指数関数あるいは対数関数などの一般的な数学演算ができます。
iex> deg_to_rad = :math.pi() / 180
0.017453292519943295
iex> sin = :math.sin(60 * deg_to_rad)
0.8660254037844386
iex> sqrt_3 = :math.sqrt(3)
1.7320508075688772
iex> sin == sqrt_3 / 2
true
iex> :math.atan2(sqrt_3, 1) / deg_to_rad
59.99999999999999
iex> x = :math.exp(10)
22026.465794806718
iex> :math.log(x)
10.0
-
:math.pi/0
: 円周率 π -
:math.sin/1
: 三角関数 sinθ (θはラジアン) -
:math.sqrt/1
: 平方根 √n -
:math.atan2/2
: atan2(y, x)で原点と座標(x, y)を結ぶ線分がx軸正方向となす角度をラジアンで返します。 -
:math.exp/1
: 指数関数 e^n -
:math.log/1
: 自然対数 ln n
queueモジュール
queue
はデータ構造で、FIFO(先入れ先出し)の両端キューを効率よく実装します。
iex> q = :queue.new
{[], []}
iex> q = :queue.in("A", q)
{["A"], []}
iex> q = :queue.in("B", q)
{["B"], ["A"]}
iex> {value, q} = :queue.out(q)
{{:value, "A"}, {[], ["B"]}}
iex> value
{:value, "A"}
iex> {value, q} = :queue.out(q)
{{:value, "B"}, {[], []}}
iex> value
{:value, "B"}
iex> {value, q} = :queue.out(q)
{:empty, {[], []}}
iex> value
:empty
-
:queue.new/0
: 空のキューをつくって返します。 -
:queue.in/2
: 項目をキューの最後に加え、新たなキューを返します。 -
:queue.out/1
: 項目をキューの最初から取り出します。戻り値は{{value, 項目}, キュー}
のかたちのタプルです。
randモジュール
ランダム値を返す関数とランダムなシードを設定する関数があります。
iex> :rand.uniform()
0.5094207040603064
iex> _ = :rand.seed(:exs1024, {123, 123534, 345345})
{%{
jump: #Function<13.15449617/1 in :rand.mk_alg/1>,
max: 18446744073709551615,
next: #Function<12.15449617/1 in :rand.mk_alg/1>,
type: :exs1024
},
{[1777391367797874666, 1964529382746821925, 7996041688159811731,
16797603918550466679, 13239206057622895956, 2190120427146910527,
18292739386017762693, 7995684206500985125, 1619687243448614582,
961993414031414042, 10239938031393579756, 12249841489256032092,
1457887945073169212, 16031477380367994289, 12526413104181201380,
16202025130717851397], []}}
iex> :rand.uniform()
0.5820506340260994
iex> :rand.uniform(6)
4
-
:rand.uniform/0
: 0.0≦x<1.0の範囲で一様分布する乱数xを浮動小数点数で返します。プロセス辞書は更新されます。 -
:rand.uniform/1
: 引数の整数N(1≦N)について、0.0≦x<Nの範囲で一様分布する整数の乱数xを返します。プロセス辞書は更新されます。 -
:rand.seed/2
: 第1引数のアルゴリズムと第2引数の整数タプルにより、プロセス辞書の乱数生成にシードを与えます。戻り値は初期状態です。
zipとzlibモジュール
zip
モジュールを用いると、メモリやディスクのZIPファイルが読み書きできます。また、ファイル情報が取り出せます。つぎのコードは、ZIPファイルの中のファイル数を数えます。
iex(75)> :zip.foldl(fn _, _, _, acc -> acc + 1 end, 0, :binary.bin_to_list("samples.zip"))
{:ok, 70}
-
:zip.foldl/3
: 第3引数のアーカイブ内のファイルに対して、第1引数のコールバック関数を呼び出します。第2引数はコールバックに渡される初期値です。コールバック関数が受け取る引数はつぎの4つです。- アーカイブ内のファイル名
- ファイルの情報を返す関数
- ファイルの中身を返す関数
- 初期値から集計された値
-
:binary.bin_to_list/1
: 引数をバイトのリストにして返します。
zlib
モジュールはzlibライブラリのAPIで、データの圧縮と解凍を扱います。
iex> song = "
...> The snow glows white on the mountain tonight
...> Not a footprint to be seen
...> A kingdom of isolation
...> And it looks like I'm the queen"
"\nThe snow glows white on the mountain tonight\nNot a footprint to be seen\nA kingdom of isolation\nA
nd it looks like I'm the queen"
iex> compressed = :zlib.compress(song)<<120, 156, 29, 204, 49, 14, 195, 48, 12, 67, 209, 221, 167, 224, 214, 115, 116,
236, 210, 169, 23, 112, 16, 197, 22, 108, 139, 77, 172, 192, 215, 175, 208,
145, 15, 248, 76, 159, 42, 152, 198, 133, 210, 185, 38, 86, 85, 23, 208, 224,
...>>
iex> byte_size(song)
127
iex> byte_size(compressed)
107
iex> :zlib.uncompress(compressed)
"\nThe snow glows white on the mountain tonight\nNot a footprint to be seen\nA kingdom of isolation\nA
nd it looks like I'm the queen"
-
:zlib.compress/1
: zlibヘッダとチェックサムでデータを圧縮します。 -
byte_size/1
: ビットストリングを納めるのに必要なバイト数を返します。 -
:zlib.uncompress/1
: zlibヘッダーとチェックサムでデータの圧縮を解除します。
Elixir入門もくじ
- Elixir入門 01: コードを書いて試してみる
- Elixir入門 02: 型の基本
- Elixir入門 03: 演算子の基本
- Elixir入門 04: パターンマッチング
- Elixir入門 05: 条件 - case/cond/if
- Elixir入門 06: バイナリと文字列および文字リスト
- Elixir入門 07: キーワードリストとマップ
- Elixir入門 08: モジュールと関数
- Elixir入門 09: 再帰
- Elixir入門 10: EnumとStream
- Elixir入門 11: プロセス
- Elixir入門 12: 入出力とファイルシステム
- Elixir入門 13: aliasとrequireおよびimport
- Elixir入門 14: モジュールの属性
- Elixir入門 15: 構造体
- Elixir入門 16: プロトコル
- Elixir入門 17: 内包表記
- Elixir入門 18: シギル
- Elixir入門 19: tryとcatchおよびrescue
- Elixir入門 20: 型の仕様とビヘイビア
- Elixir入門 21: デバッグ
- Elixir入門 22: Erlangライブラリ
- Elixir入門 23: つぎのステップ
番外
Posted on February 19, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.