ErlangVMで動くRuby風の関数型言語Elixir(エリクサー) : 基礎編
Erlangの奇妙な文法を覚えることなく、Erlangの機能が使えるエリクサー。
Ruby風の文法なのでRubyistには馴染みの関数などが使えるが、以下のことを頭にいれておくべし。
楽天Technologyカンファレンスでセッションがあったり、Erlangを簡単に書ける言語としてこれから普及していくのではないでしょうか!
インストール
brew install elixir
iex
iex
irbのようにiexで、試し書きが簡単にできます。(iexはerlのラッパー)
基本文法
四則演算
1 + 1 # 2 1 - 1 # 0 1 * 1 # 1 1 / 1 # 1.0 div 1, 1 # 1 rem 2, 4 # 2 # 2 % 4 not work
型
"a" # string 1 # integer 1.2 # float :id # atom [1,2,3] # list {1,2,3} # tuple [a: "a", b: 2] # keyword
文字列
s = "str" "[" <> s <> "]" # [str] "[#{s}]" # [str] String.reverse "str" # rts String.slice "str", 1, 2 # tr String.first "str" # f String.last "str" # r String.at "str", 1 # t String.graphemes("str") # ["s", "t", "r"]
変数
v = "v" # v = "vv" 不変なので代入不可
デバッグ
IO.inspect [1,2,3] IO.puts "foo" # 文字列のみ(改行コード付き) IO.write "foo" # 文字列のみ(改行コードなし)
コレクション
[head | tail] = [1,2,3] head # 1 tail # [2,3 Enum.map [1,2,3], fn(i) -> i * i end # [1,4,9] Enum.map [1,2,3], &(&1 * &1) # [1,4,9] Enum.filter [1,2,3], &(Integer.odd?(&1)) # [1,3] Enum.find [1,2,3], &(&1 == 1) # 1 Enum.all? [1,3], &(Integer.odd?(&1)) # true [scala = forall] Enum.any? [1,3], &(Integer.odd?(&1)) # true [scala = exists] Enum.at [1,2,3], 1 # 2 Enum.max [1,2,3] # 3 Enum.join [1,2,3], "-" # 1-2-3 f = fn i when rem(i, 2) == 0 -> [i] _ -> [] end Enum.flat_map(1..10, f) # [2, 4, 6, 8, 10] Enum.map(1..10, f) |> List.flatten # [2, 4, 6, 8, 10]
パイプ
[1,2,3,4,5] |> Enum.filter(&(rem(&1,2) != 0)) |> Enum.map(&(&1 * &1)) # [1,9,25] "str" |> String.graphemes |> Enum.map(&("-#{&1}-")) |> Enum.join # "-s--t--r-"
気軽に繋げて書くことができる。
条件
if
if true do "ok" # ok else "ng" end # 簡易版 if true, do: "ok", else: "ng" # ok if true, do: 1 # 1 if false, do: 1, else: 2 # 2
unless
unless false, do: "unless"
case
case 1 do 1 -> p "ok" # ok _ -> p "ng" end case [1,2,3] do [1 | _] -> p "ok" # ok _ -> p "ng" end case {1,2,3} do {1,2,3} -> p "ok" # ok _ -> p "ng" end case [1,2,3] do [_ | [2,3]] -> p "ok" _ -> p "ng" end case [1] do [h | []] -> p h # 1 _ -> p "ng" end a = 1 case true do ^a -> p "not match" _ -> p "match" end
関数
基本
defmodule Math do def sum(a, b) do a + b end end Math.sum(1,2) # 3 defmoduleの中でないとdefは定義できない Math.sum 1,2 # rubyのように()省略可 # ネスト defmodule Math do defmodule Foo do def sum(a, b) do a + b end end end Math.Foo.sum 1,2 # 3 # 短く defmodule Math do def sum(a, b), do: a + b end Math.sum 1, 2 # 3
匿名関数
f = fn(x, y) -> x + y end f.(1,2) # 3 # 短く f = &(&1 + &2) f.(1,2) # 3
高階関数
ff = fn(f) -> f.(2,3) + f.(4,5) end ff.(f) # 14
ガード
f2 = fn x when x < 1 -> "ng" _ -> "ok" end f2.(1) # ok
サンプル
# フィボナッチ defmodule Fib do def f(l), do: f(l,1,1) def f(l, a, b) do if l > b, do: [b] ++ f(l, b, a + b), else: [] end end Fib.f(30) # [1, 2, 3, 5, 8, 13, 21]
# リバース defmodule Reverse do def r([head | tail]), do: r(tail) ++ [head] def r([]), do: [] end Reverse.r [1,2,3] # [3,2,1] Enum.reverse [1,2,3] # [3,2,1]
クラスのようなもの
defrecord Person, name: "", age: 0 do def say(mine) do "I am " <> mine.name <> "." end end tanaka = Person.new(name: "tanaka", age: 20) tanaka.say # I am tanaka.