pythonエンジニアの自分がelixirを(ちょっとだけ)開発できるようになった時の勉強メモ

# 目的
お世話になっているソシャゲ会社様がelixirに力を入れており、実務で触る機会をいただきました。

今まで、pythonをメインとしてjava、php、c#などでも開発したことがあり、**1つの言語が分かっていれば比較的簡単に応用できる**と思っていましたが、elixirは**暗号にしか見えない**状態で、持論はあっさり崩れました。

pythonの開発に戻ることになり、キレイサッパリ忘れてしまいそうなので、「**pythonとの対比**」でメモしておこうと思います。

登場する例はかなり極端にしてあり、実務レベルではないのでご注意ください:sob:

# pythonとの違いに注意した4点
## 関数型言語である
pythonは `オブジェクト指向型言語` ですが、elixirは `関数型言語` です。
elixirにはクラスはありませんし、もちろんインスタンスもありません。

設計レベルで頭を切り替えることを、常に意識しておくことが重要だなと思いました。

## 変数のスコープが狭い
配列の全要素値を合計したい場合、シンプルに考えるとこんな感じになると思います。

```python:pythonの場合
sum = 0

for x in [1, 2, 3, 4, 5]:
    sum += x

print sum
# 15
```

```elixir:elixirの場合
sum = 0

for x <- [1, 2, 3, 4, 5] do
  sum = sum + x
end

IO.inspect sum
# 0
```

同じ書き方なのに、elixirの結果はまさかの**ゼロ**。

これは、for内が別スコープなので、sumが別変数扱いになっているためです。

elixirは、for内（do内）は関数ということなので、pythonで強引に表現するとこんな感じになるかと思います。
こう見ると当然の結果ではありますね。

```python:pythonで強引に表現
def do_sum(x, y):
    sum = x + y

sum = 0

for x in [1, 2, 3, 4, 5]:
    do_sum(sum, x)

print sum
# 0
```

実務で、配列をループさせてゴニョゴニョ…はよく行うことなので、どうするべきなのか迷いました。

だがしかし、elixirには「要素を順番に抜き出して処理する」という考えがあり、それに伴う関数が充実しているので問題ありませんでした。

例えば、要素を順番に処理していく [`Enum.reduce/2`](https://hexdocs.pm/elixir/Enum.html#reduce/2) 関数。

各要素は、第1引数の変数xに渡されてきます。
また、各要素の戻り値はアキュムレータ（第2引数の変数acc）に保存されて渡されていきます。

```elixir:Enum.reduce/1を使った例
sum = Enum.reduce([1, 2, 3, 4, 5], fn(x, acc) -> x+acc end)
# 15
```

実行イメージは、こう考えると分かりやすいかなと思います。

```elixir:Enum.reduceの実行イメージ
sum = (5 + (4 + (3 + (2 + 1))))
# 15
```

まぁ、この例の場合は [`Enum.sum/1`](https://hexdocs.pm/elixir/Enum.html#sum/1) 関数がベストなわけですが！

```elixir:Enum.sum/1を使った例
sum = Enum.sum([1, 2, 3, 4, 5])
# 15
```

## _ (アンダースコア) 1つで始まっている変数の意味
例えば `_hoge` という変数が定義してあったとします。
pythonでは「インスタンス外からアクセスされない変数」という意味ですが、elixirは「使用されない変数」という意味になります。

```python:pythonの場合
class Test(object):
    _hoge = "called hello"

    @classmethod
    def hello(cls):
        print cls._hoge

print Test._hoge  # pepにかけると `Access to a protected member _hoge of a class` とのwarning
```

```elixir:elixirの場合
defmodule Test do
  # 引数の変数は使用されていないので、名前を`hoge`に変えた場合、
  # コンパイルしようとすると `warning: variable "hoge" is unused` とwarningが表示されます。
  def hello(_hoge) do
    IO.inspect "called hello"
  end
end
```

## 右辺を省略した場合のbool比較
pythonは変数値がゼロの場合も`False`になりますが、elixirは**falseとnil以外は真**なので`true`になります。

```python:pythonの場合
hoge = 0

if hoge:
    print True
else:
    print False

# False
```

```elixir:elixirの場合
hoge = 0

if hoge do
  :true
else
  :false
end

# true
```

# pythonには無い考えで重要な4点
## パターンマッチング
これが理解できないとelixirでの開発はできないと言ってもいいレベル。最重要です。

### 変数の代入もマッチング
例えば、変数への代入もマッチングが行われています。
この例だと、変数 `a` に `1` をマッチングして、エラーにならなければ代入（束縛）されます。

```elixir:変数aに1をマッチング→代入
a = 1
```

とは言っても、python同様、elixirの変数には型宣言が無いので、エラーになることはあり得ません。
そのため、最初は全く理解できませんでした。

もうちょっと理解しやすいように、配列を例にします。

この例だと、右辺・左辺共に配列の要素が3つなので、エラーなくマッチして代入されます。

```elixir:正常にマッチング
[one, two, three] = [1, 2, 3]

IO.inspect one
# 1

IO.inspect two
# 2

IO.inspect three
# 3
```

しかし、左辺と右辺の要素数が異なる場合、マッチエラーになります。

```elixir:マッチエラー
[one, two] = [1, 2, 3]

** (MatchError) no match of right hand side value: [1, 2, 3]
```

また、パイプ記号 `|` は特殊で、配列を分割してマッチします。
`one` に最初の要素の値、`tail` に残りの配列が割り当てられます。

```elixir:パイプ記号で配列を分割して変数に代入
[one | tail] = [1, 2, 3]

IO.inspect one
# 1

IO.inspect tail
# [2, 3]
```

### どう使われる？
ここまでの例を見ると、「代入用の機能？」と思うかもしれませんが、実は「caseの分岐チェック」や「オーバーロードされた関数の引数」で使われる方がメイン・かつ強力です。

```elixir:caseの分岐でパターンマッチ
defmodule Test do
  def hoge(arg) do
    case arg do
      [a, b, c] -> a + b + c
      [a, b] -> a * b
    end
  end
end

Test.hoge([1, 2, 3])   # [a, b, c]条件にマッチ
# 6

Test.hoge([2, 4])      # [a, b]条件にマッチ
# 8
```

```elixir:関数の引数でパターンマッチ
defmodule Test do
  def hoge([a, b, c]) do
    a + b + c
  end

  def hoge([a, b]) do
    a * b
  end
end

Test.hoge([1, 2, 3])   # [a, b, c]引数のhoge関数にマッチ
# 6

Test.hoge([2, 4])      # [a, b]引数のhoge関数にマッチ
# 8
```

## パイプライン
### パイプラインとは？
シェルのパイプと似ています。
関数の戻り値を、パイプラインで指定された関数の第1引数に渡すことができます。

### どう使われる？
例えば、「配列値をソートしたうえで要素を逆順にする」場合、まず[`Enum.sort/1`](https://hexdocs.pm/elixir/Enum.html#sort/1)関数を実行して、その結果を[`Enum.reverse/1`](https://hexdocs.pm/elixir/Enum.html#reverse/1)関数に渡します。
すると、括弧がネストして読みにくい状態になります。

```elixir:パイプラインを使わない例
Enum.reverse(Enum.sort([2, 4, 1, 3, 5]))
# [5, 4, 3, 2, 1]
```

パイプラインを使うとシンプルな記述になり、可読性が上がります。

```elixir:パイプラインを使うと
[2, 4, 1, 3, 5] |> Enum.sort |> Enum.reverse
# [5, 4, 3, 2, 1]
```

この例だと関数が2つだけなので効果は薄いですが、実務だと5個以上の関数を使用することもあり、劇的に変わります。

自分で関数を作る場合も、第一引数を何にするのかが重要だと思いました

## atom（アトム）
### atomとは？
主に文字列にコロン記号 `:` を前置して定義したものです。
例えば、 `:hoge` 。これはatomになります。
宣言不要で、記述したら即使用可能になります。

```elixir:atomの確認
:hoge |> is_atom
# true

:hoge == :"hoge"
# true

i :hoge
# Term
#   :hoge
# Data type
#   Atom
# Reference modules
#   Atom
# Implemented protocols
#   IEx.Info, List.Chars, Inspect, String.Chars
```

### どう使われる？
case文の条件（パターンマッチ）として使用されることが多いと思います。

```elixir:atomをcaseで使用する例
defmodule Test do
  def hoge(arg) do
    case arg do
      {:ok, value} -> "#{value} is hoge!"
      {:ng, _} -> "ng!"
      _ -> :err
    end
  end
end

{:ok, 12345} |> Test.hoge   # {:ok, value}の条件にマッチする
# "12345 is hoge!"

{:ng, 12345} |> Test.hoge   # {:ng, _}の条件にマッチする
# "ng!"

:err |> Test.hoge           # _の条件にマッチする
# :err
```

### 補足
意識する必要はありませんが、bool値はatomです。

```elixir:boolean値がatomであることを確認
false |> is_atom
# true

false == :false
# true

false == :"false"
# true

:false |> is_boolean
# true

i true
# Term
#   true
# Data type
#   Atom
# Reference modules
#   Atom
# Implemented protocols
#   IEx.Info, List.Chars, Inspect, String.Chars
```

モジュールも、自動的にatomになりますが、これも意識する必要はありません。

```elixir:モジュールがatomであることを確認
defmodule Test do
  def hello() do
    "called hello!"
  end
end

Test |> is_atom
# true

i Test
# Term
#   Test
# Data type
#   Atom
# Module bytecode
#   []
# Source
#   iex
# Version
#   [59884929836438387182517456501295609178]
# Compile options
#   []
# Description
#   Call Test.module_info() to access metadata.
# Raw representation
#   :"Elixir.Test"
# Reference modules
#   Module, Atom
# Implemented protocols
#   IEx.Info, List.Chars, Inspect, String.Chars
```

```elixir:関数をatomで実行
Test.hello()
# "called hello!"

:"Elixir.Test".hello()
# "called hello!"
```

## アリティ
### アリティとは？
アリティは、関数の「引数の数」です。
elixirはオーバーロード可能なので、対象の関数は名前だけでは特定できません。`名前＋アリティ` で特定されます。

例えば、`Test.hello`関数に、引数が1つのものと2つのものがある場合、引数1つは `Test.hello/1`、2つは `Test.hello/2` と表現されます。

```elixir:アリティ例
defmodule Test do
  def hello(arg1) do
    "この関数は Test.hello/1"
  end

  def hello(arg1, arg2) do
    "この関数は Test.hello/2"
  end
end
```

### どう使われる？
例えば、関数を変数に代入する場合に登場します。
配列値を加算する [`Enum.sum/1`](https://hexdocs.pm/elixir/Enum.html#sum/1)を代入させる場合、以下のようにします。

```elixir:関数を変数に代入する例
f = &Enum.sum/1

f.([1, 2, 3, 4, 5])
# 15
```

# pythonと似ていて知っていると助かる2点
## コマンドラインインターフェース
pythonと同様に、コマンドラインインターフェースが用意されています。
対話式でコードを試せるので、超絶助かります。

```shell:pythonのコマンドライン
$ python

Python 2.7.10 (default, Jul 15 2017, 17:16:57)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
```

```shell:elixirのコマンドライン
$ iex

Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

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

## コード規約
pythonの `pep8` のように、言語レベルでのコード規約 `code formatter` が用意されています。
プロジェクト毎に規約を用意する必要もなく、自動で修正も行ってくれるので便利です。

```shell:コード規約チェックを実行
$ mix format --check-formatted
```

```shell:コード規約に沿ってhoge.exsを自動修正
$ mix format hoge.exs
```

# 基本構文の違い
基本構文は言語によって当然違うので、どのみち勉強する必要ありな部分です。
「pythonとの対比」という目的とはちょっとズレますが、備忘録としてメモさせてください。

## モジュール・関数
モジュールは `defmodule`、関数は `def`（外部からアクセスされない関数は `defp`）で宣言します。

elixirには`return`が無く、関数の戻り値は、関数内で**最後に実行された行**になります。

## モジュールと関数の基本例
```elixir:elixir例
defmodule Test do
  def hoge() do
    :ok
  end
end

Test.hoge() |> IO.inspect
# :ok
```

pythonの以下とほぼ同じです。

```python:python例
class Test(object):
    @classmethod
    def hoge(cls):
        return "ok"

print Test.hoge()
# "ok"
```

## 関数の引数にデフォルト値を指定したい場合
引数を省略した場合のデフォルト値を指定する際は、`\\` を使用します。

```elixir:elixir例
defmodule Test do
  def hoge(foo, bar \\ 10) do
    foo + bar
  end
end

Test.hoge(5) |> IO.inspect
# 15
```

```python:python例
class Test(object):
    @classmethod
    def hoge(cls, foo, bar=10):
        return foo + bar

print Test.hoge(5)
# 15
```

## bool値を返す関数
elixirでは、bool値を返す関数の場合、名前の後ろに `?`（クエスチョンマーク）を付ける慣習があります。
付けないからといって、エラーになったり `code formatter` のチェックに引っかかったりすることはありません。

```elixir:elixirでbool値を返す関数例
defmodule Test do
  def hoge?() do
    false
  end
end

Test.hoge?()
# false
```

## エラーを返す関数
同様に、例外が発生する場合、名前の後ろに `!`（エクスクラメーションマーク）を付ける慣習があります。
例えば、「連想配列からkey指定で値を取得する」 [`Map.fetch/2`](https://hexdocs.pm/elixir/Map.html#fetch/2) 関数には、`!` ありとなしのバージョンが用意されているので例として使わせていただきます。

```elixir:!ありバージョン。keyが存在しない場合はKeyErrorがraiseされる
%{} |> Map.fetch!(:hoge)
# ** (KeyError) key :hoge not found in: %{}
#     (stdlib) :maps.get(:hoge, %{})
```

```elixir:!なしバージョン。keyが存在しない場合はatomを返す
%{} |> Map.fetch(:hoge)
# :error
```

## for文
### 固定値ループ
1〜10でループさせる方法です。

```elixir:elixir例
out =
  for x <- 1..10 do
    x
  end

out |> IO.inspect
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

```python:python例
# アウトプットを合わせるために配列にセットしているのでイコールではないですが...

out = []
for x in range(1, 11):
    out.append(x)

print out
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

### 内包表記
pythonと違って実行速度が速いわけではないので、内包表記にするかどうは可読性重視です。

#### 内包表記の基本形
先程の固定値ループの例を内包表記にしています。

```elixir:elixirで固定値ループを内包表記
out = for x <- 1..10, do: x

out |> IO.inspect
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

```python:python例
out = [x for x in range(1, 11)]

print out
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

#### 内包表記で絞り込みを行う方法
2の倍数のみで絞り込む例です。

```elixir:elixir例
out = for i <- 1..10, rem(i, 2) == 0, do: i

out |> IO.inspect
# [2, 4, 6, 8, 10]
```

```python:python例
out = [i for i in range(1, 11) if i % 2 == 0]

print out
# [2, 4, 6, 8, 10]
```

## List（配列）
### 宣言方法
```elixir:elixir、python共同じ
list = [1, 2, 3, 4, 5]
```

### 配列要素をループさせる
```elixir:elixir例
out =
  for x <- [1, 2, 3, 4, 5] do
    x * 10
  end

out |> IO.inspect
# [10, 20, 30, 40, 50]
```

```python:python例
out = []

for x in [1, 2, 3, 4, 5]:
    out.append(x * 10)

print out
# [10, 20, 30, 40, 50]
```

ちなみに、同じことを内包表記でやると...

```elixir:elixir例
out = for i <- [1, 2, 3, 4, 5], do: i * 10

out |> IO.inspect
# [10, 20, 30, 40, 50]
```

```python:python例
out = [x * 10 for x in [1, 2, 3, 4, 5]]

print out
# [10, 20, 30, 40, 50]
```

### index値と一緒にループさせる
```elixir:elixir例
for {data, index} <- Enum.with_index([1, 2, 3, 4, 5]) do
  "#{index} -> #{data}" |> IO.inspect
end

# "0 -> 1"
# "1 -> 2"
# "2 -> 3"
# "3 -> 4"
# "4 -> 5"
```

```python:python例
for index, data in enumerate([1, 2, 3, 4, 5]):
    print "{} -> {}".format(index, data)

# 0 -> 1
# 1 -> 2
# 2 -> 3
# 3 -> 4
# 4 -> 5
```

### 要素数を取得
```elixir:elixir例
length([1, 2, 3, 4, 5])
# 5
```

```python:python例
len([1, 2, 3, 4, 5])
# 5
```

### 要素の存在チェック
```elixir:elixir、python共同じ
1 in [1, 2, 3, 4, 5]
# true

6 in [1, 2, 3, 4, 5]
# false
```

### 配列の結合
elixirの配列はLinkedListなので、大量要素を持つ配列の後ろに結合すると遅くなる点に注意です。

```elixir:elixir例
[5, 6, 7, 8, 9, 10] ++ [1, 2, 3, 4, 5]
# [5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5]

[5, 6, 7, 8, 9, 10] |> Enum.concat([1, 2, 3, 4, 5])
# [5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
```

```python:python例
[5, 6, 7, 8, 9, 10] + [1, 2, 3, 4, 5]
# [5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
```

### その他の便利関数
既に例で使っていますが、Enumモジュールが非常に便利です。
配列操作に必要なことはほぼ網羅されています。
https://hexdocs.pm/elixir/Enum.html

## Map（連想配列）
pythonでいうところのdictです。

### 宣言と値の取得方法
elixirでは、keyを文字列で設定する場合と、atomで設定する場合で書式が異なります。
ただ、実務上、文字列で設定することはなさそうだったので省略します。
以下の例のkeyの `hoge:` と `hello:` は、コロンが後ろにありますがatomです。

```elixir:elixir例
map = %{
  hoge: "hogehoge",
  hello: "world"
}
# %{hello: "world", hoge: "hogehoge"}

map.hoge |> IO.inspect
# "hogehoge"

map.hello |> IO.inspect
# "world"
```

```python:python例
map = {
    'hoge': 'hogehoge',
    'hello': 'world'
}
# {'hello': 'world', 'hoge': 'hogehoge'}

print map['hoge']
# hogehoge

print map['hello']
# world
```

### 要素を追加・更新する
指定したkeyが存在していれば値を更新、存在していなければ要素を追加します。

```elixir:elixir例
map = %{
  hoge: "hogehoge",
  hello: "world"
}
# %{hello: "world", hoge: "hogehoge"}

# 更新
map = Map.put(map, :hoge, "hoge2")
# %{hello: "world", hoge: "hoge2"}

# 追加
map = Map.put(map, :foo, "bar")
# %{foo: "bar", hello: "world", hoge: "hoge2"}
```

```python:python例
map = {
    'hoge': 'hogehoge',
    'hello': 'world'
}
# {'hello': 'world', 'hoge': 'hogehoge'}

# 更新
map.update({
    'hoge': 'hoge2'
})
# {'hello': 'world', 'hoge': 'hoge2'}

# 追加
map.update({
    'foo': 'bar'
})
# {'foo': 'bar', 'hello': 'world', 'hoge': 'hoge2'}
```

### その他の便利関数
配列のEnumモジュール同様、Mapモジュールがあります。
https://hexdocs.pm/elixir/Map.html

## tuple（タプル）
pythonと記号が異なるだけで、全く同じです。

```elixir:elixir例
{a, b} = {1, 2}

a |> IO.inspect
# 1

b |> IO.inspect
# 2
```

```python:python例
(a, b) = (1, 2)

print a
# 1

print b
# 2
```

## キーワードリスト
これはpythonには無い考えですが、elixirでは必須なのでメモしておきます。

### キーワードリストとは？
配列なのに、Mapと同様、key、value形式になっています。

```elixir:キーワードリスト例
kwargs = [a: 1, b: 2, c: 3]
# [a: 1, b: 2, c: 3]
```

ただ、Mapと異なり、keyの重複が可能です。

```elixir:キーワードリスト重複例
kwargs = [a: 1, b: 2, c: 3, c: 5]
# [a: 1, b: 2, c: 3, c: 5]
```

内部的には、{key、value} の2要素のタプルを配列で管理しています。
つまり、 `[a: 1, b: 2]` と `[{:a, 1}, {:b, 2}]` は同意です。

```elixir:タプル形式とのイコール確認
[a: 1, b: 2, c: 3] === [{:a, 1}, {:b, 2}, {:c, 3}]
# true
```

### 宣言と値の取得方法
```elixir:キーワードリスト例
kwargs = [a: 1, b: 2]
# [a: 1, b: 2]

kwargs[:b]
# 2
```

### 要素の追加方法
```elixir:要素の追加例
kwargs = [a: 1, b: 2]

kwargs = [c: 3] ++ kwargs
# [c: 3, a: 1, b: 2]
```

### 要素を切り出す方法
要素を抜き出しつつ、抜き出した要素を削除したキーワードリストも返します。

```elixir:要素の切り出し
kwargs = [hello: "world", hoge: "hogehoge", foo: "bar"]
# [hello: "world", hoge: "hogehoge", foo: "bar"]

{hoge, kwargs} = Keyword.pop(kwargs, :hoge, [])

hoge |> IO.inspect
# "world"

kwargs |> IO.inspect
# [hello: "world", foo: "bar"]
```

### 要素を削除する方法
```elixir:要素の削除例
kwargs = [a: 1, b: 2]
# [a: 1, b: 2]

kwargs = Keyword.delete(kwargs, :b)
# [a: 1]
```

### その他の便利関数
Keywordモジュールを参照してください。
https://hexdocs.pm/elixir/Keyword.html

## 構造体
pythonには存在しない考えです。

クラスの雰囲気で作れますが、当然ながらクラスではありません。
データ構造を保証する仕組みです。

```elixir:構造体の使用例
# 構造体の定義
defmodule Player do
  defstruct [name: "default", level: 1]
end

player = %Player{name: "Hoge", level: 10}
# %Player{level: 10, name: "Hoge"}

player = %Player{name: "hello"}
# %Player{level: 1, name: "hello"}

player.__struct__
Player
```

実はMapですので、Mapを操作する関数は全て使用可能です。

```elixir:構造体がMapであることを確認
%Player{} |> is_map
# true
```

## 処理分岐

### cond do文
分岐の条件に**複数の変数**や**複数の条件パターン**が絡む場合は、`cond do` を使用します。
この分岐はpythonには存在しません。

上の条件から順にマッチングさせ、マッチングした条件の処理が実行されます。
もし、全ての条件にマッチしない場合、`CondClauseError`がraiseされますので、それが問題であれば `true` を条件に入れておく必要があります。

```elixir:elixirのcond_do例
x = false
y = true

type =
  cond do
    x == true -> :select_x
    y == true -> :select_y
    true -> nil              # 何もマッチしないと CondClauseError になるので用意
  end

type |> IO.inspect
# :select_y
```

### case文
**1つの変数に対するパターンマッチ**で分岐させたい場合は、`case` を使用します。
こちらもpythonには存在しません。

`cond do`同様、全ての条件にマッチしない場合、`CondClauseError`がraiseされます。

```elixir:elixirのcase例
result = {:ok, "Hello, World"}

message =
  case result do
    {:ok, msg} -> msg
    {:error, msg} -> "error!: #{msg}"
    _ -> :nil                            # 何もマッチしないと CondClauseError になるので用意
  end

message |> IO.inspect
# "Hello, World"
```

### if文
caseでのパターンマッチが強力なため、実務では、あまりif文を使う機会は無い気がします。
elixirには三項演算子が存在しないため、三項演算子の代わりに使用することが多そうです。

```elixir:elixir例
age = 20

course = if age >= 20, do: :adult, else: :young

course |> IO.inspect
# :adult
```

```python:python例
age = 20

course = "adult" if age >= 20 else "young"

print course
# "adult"
```

### unless文
if文の否定型（pythonでいう`if not`）を使いたい場合、elixirでは `unless` を使用します。

```elixir:elixir例
age = 20

course = unless age < 20, do: :adult, else: :young

course |> IO.inspect
# :adult
```

```python:python例
age = 20

course = "adult" if not age < 20 else "young"

print course
# "adult"
```

## 定数
`@` を使用します。

```elixir:elixir例
defmodule Test do
  @name "testだよ！"
  
  def get_name() do
    @name
  end
end

Test.get_name() |> IO.inspect
# "testだよ！"
```

```python:python例（厳密に定数なのではなく慣例ですが！）
class Test(object):
    NAME = 'testだよ！'

    @classmethod
    def get_name(cls):
        return cls.NAME

print Test.get_name()
# 'testだよ！'
```

# まとめ
以上で、基礎的な開発が可能になる知識が身に付いた気がします。
ですが、ベース部分を作成するとなると、更に以下のようなノウハウが必要になるかと思います。

* mix   
  [Introduction to Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html)
* フレームワークPhoenix（フェニックス）    
  [Phoenix Framework](http://phoenixframework.org/)
* DB操作を行うEcto   
  [elixir - Ecto docs](https://hexdocs.pm/ecto/Ecto.html)
* useやrequireを使用した、macroの知識   
  [elixir - macros](https://elixir-lang.org/getting-started/meta/macros.html)

それぞれで1記事が必要なレベル量になってしまうので、需要がありそうだったら別途まとめようかと思います。

# 参考サイト
[Elixir School 日本語訳](https://elixirschool.com/ja/)