Elixir覚え書き

Elixirを少しやってみたので覚え書き

# 基本
- 数値：1
- 浮動小数点数：3.14
- 文字列："hoge"
- 真理値：true or false
- アトム（シンボル）：`:atom`
- リスト：[3.14, :hoge, "fuga"]
- タプル：{3.14, :hoge, "fuga"}
- キーワードリスト：[foo: "bar", hoge: 300]
    - キーがアトム限定の連想配列のようなもの
    - キーの順序は保持される
    - キーが一意かは保証されない
- マップ：%{:foo => "bar", "hoge" => 300}
    - キーは何でもいい
    - 順序付けされない
    - 重複キーは新しい値に置き換えられる

- do ～ endが基本
    - do:～　でワンライナー
- 関数の括弧も判別できれば省略可
    - `func(a)`も`func a`も可
- 特殊な記号
    - _  &  ..  |>  |  ->  <-  ^

#IEx
iexというコマンドでインタラクティブにElixirを試せる。
そればかりかiコマンドやhコマンドでそのオブジェクト（という呼び方が正しいかは知らない）の使い方まで教えてくれる。
試しに`i "hoge"`とすると"hoge"が文字列であることを教えてくれたり、Stringのヘルプを参照するといいよと教えてくれる。
なので`h String`とすると、ElixirのStringはUTF-8だよ、とかいろいろ教えてくれる。
iexちゃんマジ天使。
なのでとりあえず別ウィンドウでiexを常に走らせておく。困ったら彼女に聞こう。

# Mix
mixという諸々をやってくれる装置がある。
アプリを生成したりパッケージの依存関係を解決したりライブラリをインストールしたり……
Rubyのgemやrakeがまとめて入ってるみたいな感じだろうか（イメージ）
実際にgemっぽい動きをしているのはhexというものらしいが今はいいか。
`mix help`でコマンドのヘルプが出せる。
とりあえず`mix new app_name`でアプリのディレクトリを作って初期化してくれること、`mix run filename`でファイルを実行してくれることはわかった。
実際にnewしてみよう。アプリの名前はとりあえずboardで。

```
hoge>mix new board
* creating README.md
...
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd board
    mix test
```
ファイルが出来たのでテストを走らせてみよとのこと。

## テスト
```
board> mix test
Compiling 1 file (.ex)
Generated board app
.

Finished in 0.04 seconds
1 test, 0 failures
```
1つのテストが走った。テスト駆動開発もバッチリだな！
ま、テストの中身(text/board_text.exs)は`1 + 1 == 2`というテストだったので通って当然だけど…。

## 実装
lib/board.exにいろいろ書いてみよう。まずはFizzBuzz。

```elixir:lib/board.ex
defmodule Board do
  @moduledoc """
  Elixirの練習
  """
  
  def fizzbuzz(n) do
    cond do
      rem(n, 15) == 0 -> "FizzBuzz"
      rem(n, 3) == 0 -> "Fizz"
      rem(n, 5) == 0 -> "Buzz"
      true -> to_string(n)
    end
  end

  def upto(max) do
    for i <- 1..max do
      IO.puts(fizzbuzz(i))
    end
  end
end
```
* ruby同様、doで始まりendで終わる。
* 関数はモジュールに属していないといけないらしいので、defmoduleで囲う。
* `cond`はswitch文みたいなものか。
    * 上から判定していき、trueになったら矢印の右側の値を返す。
    * defaultに相当するものとして、一番下にtrueを書く。
* for文があり、C#のforeachに似ている。
* `1..max`はrubyなどにもある範囲（Range)オブジェクト。`1..3`なら[1,2,3]を一発で表現できる。
* 標準出力は`IO.puts`で行う。

### 実行
コマンド`mix run -e "Board.upto(30)"`で30までのFizzBuzzを実行できる。
あるいは、`iex -S mix`とすれば、iexが俺のアプリを読み込んでくれるので、iex上で
`Board.upto(30)`とすれば結果が返ってくる。iexちゃん天使すぎる。
毎回コマンドを指定していられなくなったら、main.exsとか適当なスクリプトを作り、

```elixir:main.exs
Board.upto(30)
```
と保存した後`mix run "main.exs"`とすれば実行される。

つまり
- mix run -e "コード"
- `iex -S mix`の中でコードを実行
- mix run "ファイルパス"
のいずれかで実行できる。

# Enum
こういうリスト的なやつはEnumが便利。
Enumを使うとよりきれいに書ける。

```elixir
def upto(max) do
    Enum.each(1..max, fn i -> IO.puts fizzbuzz(i) end)
end
```
Enum.eachは列挙(enumerable)と関数(Function)を渡すことで列挙の各要素に関数を適用できる。
C#でいうListのForEachかな。
列挙はさっきの範囲やリストのような続きものの総称。
関数は今回は匿名関数を使っている。
`fn 引数 -> 処理 end`で書けるぞ。
C#にも似たようなのがあるよね。

```C#
list.ForEach(i => Console.WriteLine(i));
```
みたいな。

ちなみにFunctionは宣言した関数にアンパサンドと引数を付けても得られるので、匿名関数でなく出力する関数を作ってやって

```elixir
  def print(i) do
    IO.puts fizzbuzz(i)
  end

  def upto(max) do
    Enum.each(1..max, &print(&1))
  end
  # あるいは
  def upto(max) do
    Enum.each(1..max, &print/1)
  end
```
なんてしても動く

# パイプ演算子
`IO.puts(fizzbuzz(i))`みたいな結果を次の関数の引数にするようなモノはパイプでつなげよう。
`|>`という演算子を使うと、左辺を右辺の関数の第1引数にできる。
`IO.puts(fizzbuzz(i))`は`i |> fizzbuzz |> IO.puts`となるし、
`Enum.each(1..10, &IO.puts(&1))`は`1..10 |> Enum.each(&IO.puts(&1))`になる。
で、さっきのfizzbuzzをパイプで表現すると、

```elixir
  def upto(max) do
    1..max |> Enum.each(fn i -> i |> fizzbuzz |> IO.puts end)
  end
```
となる。おー、すごい……気がする。
「１～max」を「Enum.eachして」、「fizzbuzzして」、「IO.putsで出力」と処理の流れがわかりやすくなった。

# パターンマッチ
関数型と言えばパターンマッチ。
elixirでは「=」がそれに当たる。
=は左辺と右辺の構造と値を比較して、当てはまるようなら左辺の変数を束縛（≒代入）する。
当てはまらなければMatchErrorが出る。

たとえば`a = 1`なら、左辺は変数（なにかしらの値）、右辺は数値の１なので何事もなくaに1が束縛される。
`{1, a} = {1, 2}`なら、左辺は「1と何かしらの値」、右辺は「1と2」なので滞りなくaに2が束縛される。
`{2, a} = {3, 2}`だと、左辺が「2と何かしらの値」となっているのに右辺が「1と2」になっていて、左辺の2と右辺の3がマッチしないのでエラーになる。

あと、変数としてマッチしたいけど値として残したくはないときは`_`という特殊な変数を使う。
`_ = 1`とするとマッチはするが `_`を後から参照できない。

つってもリストの総数わかんねーからマッチできねー！ってときのために`|`がある。パイプで区切るとリストの途中をスキップできる。
`[a, b | t] = [1,2,3,4,5]`とすればaに1、bに2、tに`[3,4,5]`が束縛される。

左辺に比較したい変数を置いたのに束縛されちまうよ！っていうときは`^`（ピン）演算子を使う。
束縛を防いでくれるぞ。

```elixir
# MatchError
x = 1
^x = 2
```

## case
パターンマッチを使って条件分岐するのがcaseだ。
最初にマッチした値を返してくれる。
caseでFizzBuzzを書き直してみた。

```elixir
  def fizzbuzz(n) do
    case {rem(n, 3), rem(n, 5)} do
      {0, 0} -> "FizzBuzz"
      {0, _} -> "Fizz"
      {_, 0} -> "Buzz"
      _ -> to_string(n)
    end
  end
```
3で割った余りと5で割った余りのペアをcaseにかけ、「両方0なら」「3の余りが0なら」「5の余りが0なら」「それ以外なら」とパターンに分ける。
割り算1回分計算を減らせたね。

# ガード
ところでfizzbuzz("a")といった風にすると当然エラーが出る。
数値じゃないのに剰余とかはできないからだ。
でも動的型付けでどうやって型を判定しよう？
そこで使うのがガード。

`def 関数 when 条件 do `と宣言すれば関数を条件を満たしたときだけ実行できる。

```elixir
def fizzbuzz(n) when n |> is_integer do
```
とすればnが整数のときだけ実行される。

# 参考文献
- [Elixir School](https://elixirschool.com/ja/lessons/basics/basics/)
    - とりあえずココ読んどけば間違いない
- [Elixir入門](https://techno-tanoc.github.io/ex_slide/#/)
    - スライド。わかりやすい。
- [Elixirの入門の独り言 - Qiita](https://qiita.com/kuwa0224/items/875a8f7438a9229b086f)
- [ExUnit.CaptureIO](https://hexdocs.pm/ex_unit/1.0.5/ExUnit.CaptureIO.html)
- [Phoenix入門：10分で作るブログ - Qiita](https://qiita.com/tmaeda/items/e609a7c5aac91913cb7c)