すごいE本を読みつつElixirを学んでみる。

- 作者: Fred Hebert
- 出版社/メーカー: オーム社
- 発売日: 2014/08/11
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
すでにヽ(´・肉・`)ノログ さんが実施されていた。
2014/07/28/すごいE本をElixirでやる - ヽ(´・肉・`)ノログ
15/10/15現在はElixirのバージョンは 1.1.1。
1章
ErlangシェルはElixirではiex
に相当。
簡単に試せるところはiex
で試していく。
1.2 Erlangの基礎をいくつか
数値型
- 2進数は0b、8進数は0o、16進数は0xで始める。
iex(1)> 2+15 17 iex(2)> 49 * 100 4900 iex(3)> 1892-1472 420 iex(4)> 5/2 2.5 iex(5)> div(5,2) 2 iex(6)> rem(5,2) 1 iex(7)> (50*100)-4999 1 iex(8)> -(50*100-4999) -1 iex(9)> -50*(100-4999) 244950 iex(10)> 0b101010 42 iex(11)> 0o677 447 iex(12)> 0xAE 174
変化できない変数
- Erlangでは値を変数に与えることは1回しかできないがElixirでは再束縛が可能。
- Erlang同様再束縛を禁止する場合は
^
を付ける。
iex(1)> one = 1 1 iex(2)> un = uno = one = 1 1 iex(3)> un 1 iex(4)> uno 1 iex(5)> two = one + one 2 iex(6)> two = 2 2 iex(7)> two = two + 1 3
=
演算子の動作は代入ではなくmatch operator
。- 左辺が変数でパターンマッチした場合に右辺が束縛される。
- マッチしないとMatchErrorが発生する。
- 再束縛が可能、再束縛を禁止する場合は
^
すなわちpin operator
を使う。 - 再束縛可能なのでf().に相当するものは存在しない?
iex(1)> two = 2 2 iex(2)> ^two = two + 1 ** (MatchError) no match of right hand side value: 3 iex(2)> ^two = 3 ** (MatchError) no match of right hand side value: 3 iex(2)> two = 3 3
アトム
アトムはリテラルで、自分自身の名前を値として保持しています。見たままの値が得られます。それ以上の何ものでもありません。 (すごいErlangゆかいに学ぼう! 頁6より)
- Erlangは変数を大文字で、アトムを小文字で始める。Elixirではアトムは
:
で始める。 :
で始まったダブルクォートで囲った値もアトム。
iex(1)> :atom :atom iex(2)> :atoms_rule :atoms_rule iex(3)> :atoms_rule@elixir :atoms_rule@elixir iex(4)> :"Atoms can be cheated!" :"Atoms can be cheated!" iex(5)> :atom = :'atom' :atom iex(6)> :atom = :"atom" :atom
true
,false
も実際はアトム http://elixir-lang.org/getting-started/basic-types.html#atoms
iex(1)> true == :true true iex(2)> is_atom(false) true iex(3)> is_boolean(:false) true iex(4)> is_boolean(false) true
アトムはアトム表内で参照されていて、これはメモリを消費します(1アトムにつき、32ビットシステムでは4バイト、64ビットシステムでは8バイト、それぞれ消費します)。アトム表はガベージコレクトの対象にならないので、アトムはシステムが落ちるか1048577個のアトムが宣言されるまで蓄積されていきます。これはつまり、アトムは動的に生成すべきではないということを意味します。 (すごいErlangゆかいに学ぼう! 頁7より)
ブール代数と比較演算子
xor
はない。and
,or
,not
がある。and
,or
,not
はブール代数にのみ使える?その他には&&
,||
がある。
iex(1)> 5 and 5 ** (ArgumentError) argument error: 5 iex(1)> 1 and true ** (ArgumentError) argument error: 1 iex(1)> not 1 ** (ArgumentError) argument error :erlang.not(1)
iex(1)> true and false false iex(2)> false or true true iex(3)> true xor false ** (SyntaxError) iex:3: syntax error before: 'xor' iex(3)> true & false ** (SyntaxError) iex:3: syntax error before: '&' iex(3)> true && false false iex(4)> not false true iex(5)> not ( true and true) false
- 厳格な比較は
===
,!==
、そうでない場合は==
,!=
iex(1)> 5 === 5 true iex(2)> 1 === 0 false iex(3)> 1 /== 0 ** (SyntaxError) iex:3: syntax error before: '==' iex(3)> 1 /= 0 ** (SyntaxError) iex:3: syntax error before: '=' iex(3)> 1 !== 0 true iex(4)> 1 != 0 true iex(5)> 5 !== 5.0 true iex(6)> 5 != 5.0 false
要素の比較順はErlangと同様?
number < atom < reference < fun < port < pid < tuple < list < bit string 「順序は重要ではないのです-すべての並び替え順序(全順序)が明確に定義されていることが重要なのです」 (すごいErlangゆかいに学ぼう! 頁9より)
iex(1)> 1 < 2 true iex(2)> 1 < 1 false iex(3)> 1 >= 1 true iex(4)> 1 =< 1 ** (SyntaxError) iex:4: syntax error before: '<' iex(4)> 1 >= 1 true iex(5)> 1 => 1 ** (SyntaxError) iex:5: syntax error before: '=>' iex(5)> 5 + 11ama ** (SyntaxError) iex:5: syntax error before: ama iex(5)> 5 === true false iex(6)> 0 == false false iex(7)> 0 === false false iex(8)> 1 < false true
タプル
_
は気にしない変数、常に未束縛と認識されるワイルドカードのような振る舞い- アトムを1つめの要素に含むタプルは
タグ付きタプル
と呼ばれる
iex(1)> x = 10 10 iex(2)> y = 4 4 iex(3)> point = {x, y} {10, 4} iex(4)> point {10, 4} iex(5)> point = {4, 5} {4, 5} iex(6)> {x,y} = point {4, 5} iex(7)> x 4 iex(8)> {x,_} = point {4, 5} iex(9)> {_,_} = {4,5} {4, 5} iex(10)> {_,_} = {4,5,6} ** (MatchError) no match of right hand side value: {4, 5, 6} iex(10)> temperature = 23.213 23.213 iex(11)> preciseTemperature = {:celsius, 23.213} {:celsius, 23.213} iex(12)> {:kelvin, t} = preciseTemperature ** (MatchError) no match of right hand side value: {:celsius, 23.213} iex(12)> {:point, {x, y}} {:point, {4, 5}}
リスト
- リストの中の数字のうち、一つでも文字として表示できないものがあると数字のリストとして数字を表示する
iex(1)> [1,2,3, {:number, [4.5,6]}, 5.34, :atom] [1, 2, 3, {:number, [4.5, 6]}, 5.34, :atom] iex(2)> [97,98,99] 'abc' iex(3)> [97,98,99,4,5,6] [97, 98, 99, 4, 5, 6] iex(4)> [233] [233] iex(5)> [120,121,122] 'xyz'
- リストの結合は
++
,削除は--
++
,--
は右から左に実行されていく
iex(6)> [1,2,3] ++ [4,5] [1, 2, 3, 4, 5] iex(7)> [1,2,3,4,5] -- [1,2,3] [4, 5] iex(8)> [1,2,3,4,5] -- [1,3] [2, 4, 5] iex(9)> [1,2,3,4,5] -- [1,4] [2, 3, 5] iex(10)> [2,4,2] -- [2,4] [2] iex(11)> [2,4,2] -- [2,4, 2] [] iex(12)> [1,2,3] -- [1,2] --[3] [3] iex(13)> [1,2,3] -- [1,2] --[2] [2, 3] iex(14)> hd([1,2,3,4]) 1 iex(15)> tl([1,2,3,4]) [2, 3, 4] iex(16)> list = [2,3,4] [2, 3, 4] iex(17)> newList = [1|list] [1, 2, 3, 4] iex(18)> [head|tail] = newList [1, 2, 3, 4] iex(19)> head 1 iex(20)> tail [2, 3, 4] iex(21)> [newHead | newTail] = tail [2, 3, 4] iex(22)> newHead 2
|
はCons operatorと呼ばれる
iex(23)> [1|[]] [1] iex(24)> [2 | [1 | []]] [2, 1] iex(25)> [3|[2 | [1 | []]]] [3, 2, 1]
リスト内包表記
- Elixirでは
for
が使える
iex(1)> for n <- [1, 2, 3, 4], do: 2 * n [2, 4, 6, 8] iex(2)> for x <- 1..10, rem(x,2) === 0, do: x [2, 4, 6, 8, 10] iex(3)> restaurantMenu = [{:steak, 5.99}, {:beer, 3.99}, {:poutine, 3.50}, {:kit ten, 20.99}, {:water, 0.00}] [steak: 5.99, beer: 3.99, poutine: 3.5, kitten: 20.99, water: 0.0] iex(4)> for {item, price} <- restaurantMenu, price >= 3, price <= 10, do: {item, price * 1.07} [steak: 6.409300000000001, beer: 4.2693, poutine: 3.745] iex(5)> for x <- [1,2], y <- [3,4], do: x + y [4, 5, 5, 6] iex(6)> weather = [{:tronto, :rain}, {:montreal, :storms}, {:london, :fog}, {:pa ris, :sun}, {:boston, :fog}, {:vancouver, :snow}] [tronto: :rain, montreal: :storms, london: :fog, paris: :sun, boston: :fog, vanc ouver: :snow] [tronto: :rain, montreal: :storms, london: :fog, paris: :sun, boston: :fog, vancouver: :snow]
1.3 バイナリデータを扱う
ビット構文
2014/08/04/すごいE本をElixirでやる(6) - ヽ(´・肉・`)ノログ
Elixir のバイナリのパターンマッチは - (値) - (値)::(サイズ) - (値)::(型指定子リスト) - (値)::(サイズ)-(型指定子リスト)
iex(1)> color = 0xF09A29 15768105 iex(2)> pixel = <<color:24>> ** (SyntaxError) iex:2: keyword argument must be followed by space after: color iex(2)> pixel = <<color::24>> <<240, 154, 41>> iex(3)> pixel = <<color::28>> <<15, 9, 162, 9::size(4)>> iex(4)> pixel = <<color::15>> <<52, 41::size(7)>> iex(5)> pixel = <<color::12>> <<162, 9::size(4)>> iex(6)> pixel = <<color::16>> <<154, 41>> iex(7)> pixel = <<color::32>> <<0, 240, 154, 41>> iex(8)> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> iex(9)> <<pix1, pix2, pix3, pix4>> = pixels ** (MatchError) no match of right hand side value: <<213, 45, 132, 64, 76, 32, 6, 0, 0, 234, 32, 15>> iex(9)> <<pix1::24, pix2::24, pix3::24, pix4::24>> = pixels <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> iex(10)> <<r::8, g::8, b::8>> = <<pix1::24>> <<213, 45, 132>> iex(11)> r 213 iex(12)> <<r::8, rest::binary>> = pixels <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> iex(13)> r 213 iex(14)> rest <<45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> iex(15)> <<x1::unsigned>> = <<-44>> <<212>> iex(16)> <<x2::signed>> = <<-44>> <<212>> iex(17)> x2 -44 iex(18)> <<x2::integer-signed-little>> = <<-44>> <<212>> iex(19)> x2 -44 iex(20)> <<n::8-unit(1)>> = <<72>> "H" iex(21)> <<n::integer>> = <<72>> "H" iex(22)> <<y::4-little-unit(8)>> = <<72, 0, 0, 0>> <<72, 0, 0, 0>> iex(23)> y 72
ビット単位のバイナリ操作
- Bitwiseモジュールを使用する必要がある http://elixir-lang.org/docs/stable/elixir/Bitwise.html
- ビットシフトは
>>>
,右辺の正負で左右のシフトを決定する(負であれば左シフト)
iex(1)> use Bitwise nil iex(2)> bnot 1 -2 iex(3)> 1 &&& 1 1 iex(4)> 0b00100 = 0b00010 >>> -1 4
バイナリ文字列
- 使い所がわからない
iex(1)> <<"this is a binary string!">> "this is a binary string!"
バイナリ内包表記
- forが使える
2014/08/05/すごいE本をElixirでやる(7) - ヽ(´・肉・`)ノログ
for <
>>>, rem(x, 2) === 0, do: x と >>>> を繋げて書いてしまうと,パーサーが上手く文を区切ってくれないので必ずスペースを開けなければならない. あと Elixir の内包表記は何も指定しないと常にリストが返るので,バイナリを返したいときには into を指定すること.
- 返却値のデフォルトはリストだが、intoオプションを使うことで任意の構造で受け取ることができる
iex(1)> for <<x <- <<1,2,3,4,5>> >>, rem(x,2) === 0, do: x [2, 4] iex(2)> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> iex(3)> rgb = for <<r::8, g::8, b::8 <- pixels >>, do: {r, g, b} [{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}] iex(5)> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>> "helloworld" iex(9)> Enum.into(["a", "b", "c"], "") "abc"