すごいE本をElixirでやる(1章)

自分の日記で書いている[すごいE本をElixirでやる](http://niku.name/articles/2014/08/05/%E3%81%99%E3%81%94%E3%81%84E%E6%9C%AC%E3%82%92Elixir%E3%81%A7%E3%82%84%E3%82%8B%287%29)の1章が終わったのでまとめる．

# 宣伝

Elixir に興味を持ったら，だいたい毎週木曜日に ErlangVM に載っている言語に関する話題やそうでない話題でわいわいやる集まり [Sapporo.beam](http://sapporo-beam.github.io/) にも遊びにきてね．

たいしたことはできないけど，一緒に悩んだりはできる．

# 1章

## 1.1 Erlang シェルを使ってみる

- Erlang の `erl` 相当のものは Elixir だと `iex`
- Erlang の `help().` は Elixir だと `h()`

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> h()

                                  IEx.Helpers                                   

Welcome to Interactive Elixir. You are currently seeing the documentation for
the module IEx.Helpers which provides many helpers to make Elixir's shell more
joyful to work with.

This message was triggered by invoking the helper h(), usually referred to as
h/0 (since it expects 0 arguments).

There are many other helpers available:

  • c/2       — compiles a file at the given path
  • cd/1      — changes the current directory
  • clear/0   — clears the screen
  • flush/0   — flushes all messages sent to the shell
  • h/0       — prints this help message
  • h/1       — prints help for the given module, function or macro
  • l/1       — loads the given module's beam code and purges the current
    version
  • ls/0      — lists the contents of the current directory
  • ls/1      — lists the contents of the specified directory
  • pwd/0     — prints the current working directory
  • r/1       — recompiles and reloads the given module's source file
  • respawn/0 — respawns the current shell
  • s/1       — prints spec information
  • t/1       — prints type information
  • v/0       — prints the history of commands evaluated in the session
  • v/1       — retrieves the nth value from the history
  • import_file/1
    ┃         — evaluates the given file in the shell's context


Help for functions in this module can be consulted directly from the command
line, as an example, try:

┃ h(c/2)

You can also retrieve the documentation for any module or function. Try these:

┃ h(Enum)
h(Enum.reverse/1)

To learn more about IEx as a whole, just type h(IEx).
```

## 1.2 Erlang の基礎をいくつか

### 数値型

- Erlang と異なり `div`，`rem` を中置演算子として使えないので，`div(5, 2)`，`rem(5, 2)` のようにする
- 基数は `0b` から始めると 2 進数， `0o` から始めると 8 進数， `0x` から始めると 16 進数になる

```iex
Interactive Elixir (0.15.1) - 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
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
```

- 変数は小文字で書く．大文字で書くとエラーになる．
- `two = two + 1` がエラーにならないで再束縛される．Elixr で再束縛させないなら `^` から始まる [pin operator](http://elixir-lang.org/getting_started/4.html#4.3-the-pin-operator) というのを使う．
- 変数を「消す」 `f(Variable).` は iex にはなさそうだ(知ってたら教えてほしい)．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> one = 1
1
iex(2)> un = uno = one = 1
1
iex(3)> two = one + one
2
iex(4)> two = 2
2
iex(5)> two = two + 1
3
iex(6)> two
3
iex(7)> two = 2
2
iex(8)> ^two = two + 1
** (MatchError) no match of right hand side value: 3
    
iex(8)> ^two = one + 1
2
iex(9)> 47 = 45 + 3
** (MatchError) no match of right hand side value: 48
    
iex(9)> Two = 2
** (MatchError) no match of right hand side value: 2
    
iex(9)> f(two)
** (RuntimeError) undefined function: f/1
```

### アトム

- Erlang だと小文字で書くだけでアトムになる．だから変数名を小文字で始められない．
- Elixir は変数名を小文字で始められる，そのかわりアトムは `:` から始める．
- Erlang だとシングルクォートで囲った値もアトムになる．
- Elixir では `:` で始まるダブルクォートで囲った値もアトムになる．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :atom
:atom
iex(2)> :atoms_rule
:atoms_rule
iex(3)> :atoms_rule@erlang
:atoms_rule@erlang
iex(4)> :"Atoms can be cheated!"
:"Atoms can be cheated!"
iex(5)> :atom = :"atom"
:atom
```

### ブール代数と比較演算子

Elixir の演算子は [3 Basic operators](http://elixir-lang.org/getting_started/3.html) を見るとわかりやすい．

- `and` `or` は使えるけど，Erlang と違って短絡演算子になってる
- `xor` は使えなくなっていた(たぶん 0.15.0 から)
- Elixir では厳密な比較に `===` や `!==` を使う．厳密でない比較に `==` や `!=` を使う．
- Erlang とは違い `1 >= 1` に対応するのは `1 <= 1` で等号の位置が入れ替わったりしない．
- Erlang と同じで `true` と `false` はシンボルである．

おまけ．

Elixir では `true` `false` 以外でも扱える `&&` と `||` が用意されている．その場合は `false` と `nil` だけが偽として扱われる．Ruby と同じ．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
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)> not false
true
iex(4)> not (true and true)
false
iex(5)> 5 === 5
true
iex(6)> 1 === 0
false
iex(7)> 1 !== 0
true
iex(8)> 5 === 5.0
false
iex(9)> 5 == 5.0
true
iex(10)> 5 != 5.0
false
iex(11)> 1 < 2
true
iex(12)> 1 < 1
false
iex(13)> 1 >= 1
true
iex(14)> 1 =< 1
** (SyntaxError) iex:14: syntax error before: '<'
    
iex(14)> 1 <= 1
true
iex(15)> 5 + :llama
** (ArithmeticError) bad argument in arithmetic expression
    :erlang.+(5, :llama)
iex(15)> 5 === true
false
iex(16)> 1 < false
true
iex(17)> 1 and 2
** (ArgumentError) argument error: 1
    
iex(17)> 1 && 2
2
iex(18)> 1 || 2
1
iex(19)> false || 2
2
```

### タプル

特に違わないので iex の結果は貼らない．

iex の結果が見たければ[すごいE本をElixirでやる(4)](http://niku.name/articles/2014/07/31/%E3%81%99%E3%81%94%E3%81%84E%E6%9C%AC%E3%82%92Elixir%E3%81%A7%E3%82%84%E3%82%8B%284%29)には貼ってある．

### リスト

Erlang と Elixir であんまり変わらないので iex の結果は貼らない．

iex の結果が見たければ[すごいE本をElixirでやる(4)](http://niku.name/articles/2014/07/31/%E3%81%99%E3%81%94%E3%81%84E%E6%9C%AC%E3%82%92Elixir%E3%81%A7%E3%82%84%E3%82%8B%284%29)には貼ってある．

`[223]` が Erlang だと `“é”` と表示されるが，Elixir だとそのまま `[223]` と表示されたところだけ違った．

Elixir でも

```iex
iex(1)> <<233 :: utf8>>
"é"
```

とすれば同じように値を表現することはできる．(あんまりやらないだろうけど)

詳しくは [6 Binaries, strings and char lists](http://elixir-lang.org/getting_started/6.html) に書いてある．

### リスト内包表記

Elixir の内包表記のドキュメントは [18 Comprehensions](http://elixir-lang.org/getting_started/18.html) にある．

おまけ．

Elixir は範囲を表記するのに `1..10` をつかえる．詳しくは [Range](http://elixir-lang.org/docs/stable/elixir/Range.html) に書いてある．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> for n <- [1, 2, 3, 4], do: 2 * n
[2, 4, 6, 8]
iex(2)> for x <- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], rem(x, 2) === 0, do: x
[2, 4, 6, 8, 10]
iex(3)> restaurant_menu = [{: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(4)> for {item, price} <- restaurant_menu, 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}, {:paris, :sun}, {:boston, :fog}, {:vancouver, :snow}]
[tronto: :rain, montreal: :storms, london: :fog, paris: :sun, boston: :fog, vancouver: :snow]
iex(7)> foggy_places = for {x, :fog} <- weather, do: x
[:london, :boston]
iex(8)> for x <- 1..10, do: x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

### ビット構文

Elixir のバイナリのパターンマッチは [Kernel.SpecialForms.<<>>/1](http://elixir-lang.org/docs/stable/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1) が詳しい．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> color = 0xf09a29
15768105
iex(2)> pixel = <<color::24>>
<<240, 154, 41>>
iex(3)> 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(4)> <<pix1, pix2, pix3, pix4>> = pixels
** (MatchError) no match of right hand side value: <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    
iex(4)> <<pix1::24, pix2::24, pix3::24, pix4::24>> = pixels
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(5)> <<r::8, g::8, b::8>> = <<pix1::24>>
<<213, 45, 132>>
iex(6)> r
213
iex(7)> <<r::8, rest::binary>> = pixels
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(8)> r
213
iex(9)> rest
<<45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(10)> <<x1::unsigned>> = <<-44>>
<<212>>
iex(11)> <<x1::utf8>>
"Ô"
iex(12)> <<x2::signed>> = <<-44>>
<<212>>
iex(13)> x2
-44
iex(14)> <<x2::integer-signed-little>> = <<-44>>
<<212>>
iex(15)> x2
-44
iex(16)> <<n::8-unit(1)>> = <<72>>
"H"
iex(17)> n
72
iex(18)> <<n::integer>> = <<72>>
"H"
iex(19)> <<y::4-little-unit(8)>> = <<72, 0, 0, 0>>
<<72, 0, 0, 0>>
iex(20)> y
72
```

### ビット単位のバイナリ操作

Elixir でのバイナリ演算は [Bitwise](http://elixir-lang.org/docs/stable/elixir/Bitwise.html) が担っている．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> use Bitwise
nil
iex(2)> 0b00100 = bsl 0b0010, 1
4
iex(3)> 0b00001 = bsr 0b0010, 1
1
iex(4)> 0b10101 = bor 0b10001, 0b00101
21
```

### バイナリ文字列

特に語ることがない．

Elixir では [String](http://elixir-lang.org/docs/stable/elixir/String.html) を眺めるとよい．

### バイナリ内包表記

Elixir でのバイナリ内包表記の概要は [18.2 Bitstring generators](http://elixir-lang.org/getting_started/18.html#18.2-bitstring-generators) を眺めるとよい．

さらに詳しく知りたければ [Kernel.SpecialForms.for/1](http://elixir-lang.org/docs/stable/elixir/Kernel.SpecialForms.html#for/1) を見るとよい．

Elixir の内包表記は何も指定しないと常にリストが返るので，バイナリを返したいときには `into` を指定すること．

上に挙げた `Kernel.SpecialForms.for/1` に書いてある．

```iex
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
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(4)> for {r, g, b} <- rgb, into: "", do: <<r::8, g::8, b::8>>
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(5)> for bin <- [<<3, 7, 5, 4, 7>>], into: "", do: <<bin>>
** (ArgumentError) argument error
    
iex(5)> for bin <- [<<3, 7, 5, 4, 7>>], into: "", do: <<bin::binary>>
<<3, 7, 5, 4, 7>>
iex(6)> for << x <- <<3, 7, 5, 4, 7>> >>, into: "", do: <<x+1::integer>>
<<4, 8, 6, 5, 8>>
```