すごいErlangゆかいに学ぼうをelixirで書きなおしてみた(第一章)
- 作者: Fred Hebert
- 出版社/メーカー: オーム社
- 発売日: 2014/08/11
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
目次(1章)
すごいErlangゆかいに学ぼう!を
elixirで書きなおしてみる。
現時点での私のステータスとしては、
elixirの開発環境を整備したくらい。
いわゆる初心者。
Erlangに詳しい訳でもないので、
違いを記述していくというよりも、
書籍に記載されているシンタックスをelixirで書き直します。
また、これは下記の方々の完全にパクリになってしまってます。
本を買う前にググってとけって話ですね。
私よりも読みやすい記事となっていると思うので、
私の記事は余談的に閲覧していただければ。
2014/07/28/すごいE本をElixirでやる - ヽ(´・肉・`)ノログ
(仮想)環境
(作業)環境
開発環境の構築に関しては、
私が以前作成した記事を参照していただければ
Erlangシェルを使ってみる
シェルの起動
Erlangシェルの起動はerl
-> elixirではiex
シェルの終了
どちらもCtrl
+C
を2回
Erlangの基礎をいくつか
数値型
四則演算は下記のとおりですね。
気をつけたいのは、整数の同士の除算において
小数点以下まで扱っている所ですかね。
Interactive Elixir (1.2.0-dev) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> 2 + 15 17 iex(2)> 49 * 100 4900 iex(3)> 1892 - 1472 420 iex(4)> 5 / 2 2.5
整数桁のみで除算を行うには、
下記の関数を使用します。
div関数が商を、remが余りを算出します。
iex(5)> div 5, 2 2 iex(6)> div(5, 2) 2 iex(7)> rem 5, 2 1 iex(8)> rem(5, 2) 1
計算式の優先順位も通常通りです。
iex(9)> (50 * 100) - 4999 1 iex(10)> -(50 * 100 - 4999) -1 iex(11)> -50 * (100 - 4999) 244950
各種進数の扱いについて、Erlangと違いがあります。
Erlangは#
の前に扱う進数を記述します。
e.g. 2#, 8#, 16#
しかしelixirでは、下記の様に扱います。
iex(12)> 0b101010 42 iex(13)> 0o0677 447 iex(14)> 0xAE 174
変数
Erlangでは下記のような特徴があります。
- 大文字から始まる
- 変数に値を与えたら、変更できない
- 変数を消去するf関数が存在する
- 変更は出来ないが、同値であれば変数に代入する「ふり」はできる
elixirでは、下記が異なって来ます。
- 変数に再代入が可能
^
を使用することで、Erlang同様に再代入の禁止が可能
パターンマッチ
=
演算子の動作はパターンマッチとなっています。
iex(15)> one ** (CompileError) iex:15: undefined function one/0 iex(15)> one = 1 1 iex(16)> un = uno = one = 1 1 iex(17)> un 1 iex(18)> uno 1 iex(19)> one 1 iex(20)> two = one + one 2 iex(21)> two = 2 2 iex(22)> two = two + 1 3 iex(23)> two 3 iex(24)> ^two = 3 3 iex(25)> ^two = 4 ** (MatchError) no match of right hand side value: 4
基本的に、
左辺の項が変数で束縛されていなかった場合
自動的に右辺の値を変数に束縛します。
比較は結果として成功となります。
変数はメモリに値を保存。
インデックス22でErlangならエラーとなります。
(Erlangが変数を変更出来ないという仕様から)
インデックス25のパターンマッチで
左辺で再代入禁止の^
を宣言していて、値3を固定。
その上で、右辺は4でパターンマッチしません。
よってエラーが吐かれてます。
※パターンマッチについての詳細な説明に関しては、下記参照の事
http://elixir-lang.org/getting-started/pattern-matching.html
また、round/trunc
を使うことで、
小数点から整数を抽出することも可能です。
iex(25)> round 3.58 4 iex(26)> trunc 3.58 3
アトム
アトムは記述したアトムの名前をそのまま保持しています。
なんかEnumみたい?とか勝手に感じた。
Erlangでは、小文字で宣言。
ダブルクォートで囲ってもアトムとして扱われる。
-> elixirでは、:
で始めます。
ダブルクォートも同様に:
の後に、
ダブルクォートで囲ってもアトムとなる。
iex(27)> :hello :hello iex(28)> :hello == :world false iex(29)> :hello == :hello true iex(31)> :"hello" :hello iex(32)> :hello == :"hello" true
引用文
アトムはアトム表内で参照されていて、
これはメモリを消費します
(1アトムにつき、32ビットで4バイト、
64ビットで8バイト)
アトム表はガベージコレクトの対象にならないので、
アトムはシステムが落ちるか1048577個のアトムが
宣言されるまで蓄積されていきます。
これはつまり、アトムは動的に生成すべきではないということを意味します。
ブール代数と比較演算子
Erlangは、and
、or
、xor
、not
が使用できる。
-> elixirでは、and
、or
、not
が使用できる。
また、elixirは追加で以下も使用することが可能である。
- boolean以外で、
&&
と||
を使用可能 - javascriptの様に厳格な比較として
===
や!==
を使用可能 - 大なり、小なりの比較
<=
と>=
型が異なる2つを比較した際は
公式に書いてあるような順序が優先されるとのこと。
number < atom < reference < functions < port < pid < tuple < maps < list < bitstring
iex(1)> true and false false iex(2)> false or true true iex(3)> true && false false iex(4)> false || true true iex(5)> not false true iex(6)> not (true and true) false iex(7)> 5 == 5 true iex(8)> 5 === 5 true iex(9)> 5 == 5.0 true iex(10)> 5 === 5.0 false iex(11)> 1 !== true true iex(12)> 1 >= 1 true iex(13)> 1 > 1 false iex(14)> 1 > false false iex(15)> 1 > true false
タプル
{}
で表記_
は気にしない変数として扱います- タプルに対するパターンマッチは、要素の長さが同じ時だけタプルを展開する
- タプルのひとつ目の要素にアトムを指定するタプルはタグ付きタプル
_
について
- 使わずに捨ててしまう値が来る場所に配置
_
は常に未束縛と認識- パターンマッチではワイルドカードだと思えばいい
iex(17)> point = {4, 5} {4, 5} iex(18)> {x, y} = point {4, 5} iex(19)> x 4 iex(20)> y 5 iex(21)> {x, _} = point {4, 5} iex(22)> {_, _} = {4, 5} {4, 5} iex(23)> temperature = 23.213 23.213 iex(24)> term = {:celsius, 23.213} {:celsius, 23.213} iex(25)> {:kelvin, T} = term ** (MatchError) no match of right hand side value: {:celsius, 23.213} iex(26)> {:point, {x, y}} {:point, {4, 5}}
リスト
- 最も使われるデータ構造
- リストの中の数字の内、一つでも文字として表示できないものがあると、数字のリストとして数字を表示する
-> Erlangでstringがないため、クソと言われる所以となっています。
elixirにはstringが存在するため解消?されてますね?
iex(30)> [1,2,3,{:number, [4,5,6]},5.34,:atom] [1, 2, 3, {:number, [4, 5, 6]}, 5.34, :atom] iex(31)> [97,98,99] 'abc' iex(32)> [97,98,99,4,5,6] [97, 98, 99, 4, 5, 6] iex(33)> [233] [233]
リストでは、結合と削除が可能で、
実行順は右からとなる。
- 結合 ->
++
- 削除 ->
--
iex(40)> [1,2,3] ++ [4,5] [1, 2, 3, 4, 5] iex(41)> [1,2,3,4,5] -- [1,2,3] [4, 5] iex(42)> [2,4,2] -- [2,4] [2] iex(43)> [1,2,3,4,5] -- [1,3,5] [2, 4]
組み込み関数(BIF)
- head -> リストの最初の要素を取得
- tail -> リストの最後の要素を取得
- length -> リストの要素数を取得
iex(50)> hd([1,2,3,4]) 1 iex(51)> tl([1,2,3,4]) [2, 3, 4] iex(86)> length([1,2,3,4]) 4
コンストラクタ |
|
はcons演算子と呼ばれる
iex(58)> list = [2,3,4] [2, 3, 4] iex(59)> newList = [1 | list] [1, 2, 3, 4] iex(60)> [head | tail] = newList [1, 2, 3, 4] iex(61)> head 1 iex(62)> tail [2, 3, 4] iex(63)> [newHead | newTail] = tail [2, 3, 4] iex(64)> newHead 2 iex(55)> [1 | []] [1] iex(56)> [2 | [1 | []]] [2, 1] iex(57)> [3 | [2 | [1 | []]]] [3, 2, 1]
リスト内包表記
簡潔に言うと、リストの組み立て、修正を綺麗に短く記述する方法
elixirでの特徴
for
を使用できる- 範囲を表記する際、
1..100
を使用できる
iex(70)> for n <- [1,2,3,4,5], do: 2 * n + 1 [3, 5, 7, 9, 11] iex(71)> for n <- [1,2,3,4,5], do: 2 * n [2, 4, 6, 8, 10] iex(72)> for n <- 1..5, do: 2 * n [2, 4, 6, 8, 10] iex(73)> restaurantMenu = [{:steak, 5.99}, {:beer, 3.99}, {:poutine, 3.50}, {:kitten, 20.99}, {:water, 0.00}] [steak: 5.99, beer: 3.99, poutine: 3.5, kitten: 20.99, water: 0.0] iex(74)> for {item, price} <- restaurantMenu, price >= 3, price <= 10, do: { item, price * 1.07} [steak: 6.409300000000001, beer: 4.2693, poutine: 3.745] iex(75)> for x <- [1,2], y <- [3,4], do: x+y [4, 5, 5, 6] iex(77)> foggyPlaces = for {x, :fog} <- weather, do: x [:london, :boston] iex(79)> foggyPlaces = for {x,y} <- weather, y == :fog, do: x [:london, :boston]
バイナリデータを扱う
使うときに記述しますね。(疲れたなんて言えない)