こんにちは!
プログラミング未経験文系出身、Elixirの国に迷い込んだ?!見習いアルケミストのaliceと申します。
今回は11月4日に発売された「WEB+DB PRESS vol131 特集『はじめてのElixir』」の第1章を読んで学んだことをまとめます。
内容まとめ
第1章では、ElixirおよびErlangの歴史と関係性、および環境構築と基本的なデータ型・コレクション型について書かれています。
再現してみた(第1章)
実行環境
・Windows 11 Home(バージョン 21H2, OS ビルド 22000.1219)
・Ubuntu v22.04 ※WSL2環境下
・Elixir v1.12.3 (compiled with Erlang/OTP 24) ※WSL2環境下
事前準備
ElixirのインストールはWSL2経由、こちらの記事を参考に実施済です。
Elixir の特徴
ElixirはErlangVM上で動く言語で、Erlangの開発の歴史を受け継いだ特徴を持っています。
すなわち、ElixirもErlangと同じく並行処理指向で分散処理指向を得意としており、マルチコア実装がしやすい言語です。
「並行処理指向」とは?
複数の計算あるいはアルゴリズムを、同一期間に同時実行させつつ相互に同調(コンカレント)させて、次の期間開始までに互いに完遂させるという計算形態のことです。1
並行計算は一つのCPUに複数のタスクを存在させて、各タスクに計算を割り振ることを指します。マルチプロセッサならば、タスクを各プロセッサに分散できるのでより効率的になります。2
「分散処理指向」とは?
複数の実行主体で矛盾なく処理を分担できるよう特別に設計されたソフトウェアを用い、処理やデータを細かい単位で複数のシステムに割り当てて同時並行に進める処理方法のことです。
単体では平凡な性能のコンピュータでも、多数を連携させて分散することにより全体としては巨大な演算性能を得ることができます。
個々の処理やデータの関連性や相互依存性が強く、ノード間のデータ送受信や全体の調整・統合処理が頻繁に必要となる科学技術シミュレーションなどは並列処理が向いており、相互の関連性が低くノード間の緊密な連携が不要な暗号解読などの処理には分散処理が向いています。3
「マルチコア実装」とは?
マルチコアプロセッサを効率良く使用して処理速度を速める実装のことです。
現代のCPUはマルチコアプロセッサとよばれる複数のコアを持つCPUが主流です。
マルチコアプロセッサは、コア数が多いほど同時並行で行える処理作業の数が増えるという特徴を持っていますが、プログラム側が同時並行で処理するようにコンピュータに指示をしていないとその良さを発揮できません。4
Iex -インタラクティブなElixir
iex(1)> h Enum.t
take/2 take_every/2 take_random/2 take_while/2 to_list/1
iexを起動してまず最も使うのはIex.Helpers。h に続けて調べたい内容を検索できます。
部分的に入力してtabキーで補完が効くのが地味に役に立ちます。
Elixirのデータ型
数値型
2進数、8進数、16進数をサポートしており、それぞれをプレフィックスをつけて呼び分けます。
2進数...0b<数値>、8進数...0o<数値>、16進数...0x<数値>
#下記はいずれも10進数で27を表す
iex(2)> 0b11011 #2進数
27
iex(3)> 0o33 #8進数
27
iex(4)> 0x1B #16進数
27
真偽値とアトム
アトムは名前がそのまま自身の値になります。
また、真偽値のtrueやfalseは、アトムの:trueや:falseと同義です。
iex(5)> true === :true
true
文字列
Elixirの文字列はUTF-8でエンコードされたバイナリです。
?に続けて文字列入力するとUnicodeのコードポイントが得られます。
iex(6)> ?a
97
iex(7)> ?A
65
iex(8)> ?雪
38634
コード内では""で囲むと文字列として認識されます。
文字列の途中に計算式を挟みたい(= 式展開したい)ときは#{}で文字列でない部分を囲みます。
iex(9)> "1 + 1"
"1 + 1"
iex(10)> "1 + 1 + #{1 + 1}"
"1 + 1 + 2"
iex(11)> "私は #{1 + 1}才です。"
"私は 2才です。"
iex(12)> age = 10
10
iex(13)> "私は #{age}才です。"
"私は 10才です。"
Elixirのコレクション型
タプル
最もよく見るのは、関数の戻り値として使われる、要素が{:ok, result}と{:error, detail} のタプルだと思います。
iex(14)> return = {:ok, "正常に処理が完了しました"}
{:ok, "正常に処理が完了しました"}
iex(15)> elem(return, 1)
"正常に処理が完了しました"
iex(16)> {x, y} = return
{:ok, "正常に処理が完了しました"}
iex(17)> x
:ok
iex(18)> y
"正常に処理が完了しました"
リスト
リストには要素の順番があり、先頭の要素(ヘッド = 頭部)とそれ以降を持つリスト(テイル = 尾部)といった再帰的な形から成ります。
要素が1つしかないリストの場合、テイルは空のリストです。
空のリストの場合、ヘッドとテイルに分けることはできません。
iex(19)> [1, 2, 3] == [3, 2, 1]
false
iex(20)> hd([1, 2, 3])
1
iex(21)> tl([1, 2, 3])
[2, 3]
iex(22)> tl([1])
[]
iex(23)> tl([])
** (ArgumentError) errors were found at the given arguments:
* 1st argument: not a nonempty list
:erlang.tl([])
キーワードリスト
キーワードリストは、要素がキーとバリュー(値)のタプルから成ります。
キーはアトムである必要があります。バリューは何でも構いません。
リストですので要素に順番があります。すなわち、キーが重複しても問題ありません。
iex(24)> keywords = [{:a, 1}, {:b, 2}, {:c, 3}, {:a, 1}, {:a, 4}]
[a: 1, b: 2, c: 3, a: 1, a: 4]
iex(25)> Keyword.get(keywords, :a)
1
iex(26)> Keyword.get_values(keywords, :a)
[1, 1, 4]
マップ
マップには要素の順番が無く、要素はキーとバリューのペアから成ります。すなわち、キーは重複できません。(キーが重複した場合、後から定義された方の要素で上書きします)
キーは何でも構いませんがマップのキーがアトムの場合は略記ができ、しかもよく見かけます。
要素の値は[]を使って取り出します。キーがアトムの場合はこちらも略記ができます。
iex(27)> names = %{"Elizabeth" => "Liz", "Thomas" => "Tom", "Daniel" => "Dan"}
%{"Daniel" => "Dan", "Elizabeth" => "Liz", "Thomas" => "Tom"}
iex(28)> names["Thomas"]
"Tom"
iex(29)> names = %{"Elizabeth" => "Liz", "Thomas" => "Tom", "Daniel" => "Dan", "Elizabeth" => "Lisa"}
warning: key "Elizabeth" will be overridden in map
iex:25
%{"Daniel" => "Dan", "Elizabeth" => "Lisa", "Thomas" => "Tom"}
iex(30)> map = %{a: 1, b: 2, c: 3} #キーがアトムの場合の、マップを定義する略記
%{a: 1, b: 2, c: 3}
iex(31)> map.a #キーがアトムの場合の、要素の値を取り出す略記
1
現時点で分からないこと
Elixirは「並行処理思考」で「分散処理指向」を得意としており、「マルチコア実装」がしやすい言語です...と書いておきながら、現時点での私は、それぞれの単語の意味を正しく理解できている自信がありません。
間違いがありましたらご指摘いただければ幸いです。
本紙の購入はこちらから
~Elixirの国のご案内~
※Elixirって何ぞや?と思ったらこちらもどぞ。未来がぎゅっと詰まった、Elixirは今年で生まれて10周年です
We Are The Alchemists, my friends!5
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽に話しかけてみてください。6