60
第1回 - 基礎だ 1 - GMO Pepabo, Inc. Joe Honzawa 2015/5/13 Elixir勉強会 Elixirだ

Elixirだ 第1回強化版 前半

  • Upload
    joenoh

  • View
    190

  • Download
    1

Embed Size (px)

Citation preview

第1回 - 基礎だ 1 -

GMO Pepabo, Inc. Joe Honzawa

2015/5/13 Elixir勉強会

Elixirだ

今回の内容> 概要 > 型と制御構文 > モジュールと関数 > パターンマッチとガード式

概要

Elixirとは> Erlang VM上で動く関数型言語 > 並列分散 > 高可用性

> 動的型付け > モダンな文法 > マクロによるメタプログラミング > プロトコルによる多態性

Elixirをつくった人

>José Valim

> 歩く生産性

> rackやrailsにもコミット

Install

> $ brew install elixir

型と制御構文

型など

型など> integer > float > atom > boolean > binary > string > list

> tuple > map > range > function > keyword list

など

IEx>ポチポチしながら聞いてね > $ iex

Integer> 10 > 0b101 > 0o12 > 0x0a

Float> 1.0 > 3.14 > 6.02e23 > 1.602e-19 > 1e3 ← これダメ

Atom> Rubyで言うSymbol > :atom > :hello > :’white spaces !?’ > nil == :nil

Boolean> true > false

> 実はatom > :true == true > :false == false

Binary> <<1>> > <<256>> == <<0>> > <<1>> == <<1::size(8)>> > <<1, 0>> == <<256::size(16)>> > <<1::float>> == <<63,240,0,0,0,0,0,0>>

String> “hello world” > “世界を征服だ”

>必ずダブルクォートしてー > “hey” == <<104,101,121>> > ‘hey’ == [104,101,121]

List> 単方向リスト > [1, 2, 3] > [true, [1, 2, 3], “hey”] > [1 | [2, 3]] == [1, 2, 3] > [1, 2 | []] == [1, 2]

> 先頭への要素追加は高速

Tuple> 値の組 > {:ok, 30} > {1, 2, 3, 4, 5}

> ランダムアクセスはO(1) > 更新や追加はコスト高

Map> %{} > %{“price”=> 3980} > map = %{price: 100, amount: 2}

> map.price > Map.get(map, :price)

> map = Map.put(map, :amount, 1)

Range> 範囲 > 1..3 > 4..-5 > 1.2 .. 3.8

> (1.5 in 1.2 .. 3.8) == true

Function>無名関数 > fn (x, y) -> x * y end > fun = &(&1 * &2) # キャプチャ記法 > fun.(3, 4) == 12 # call

>定義済み関数のキャプチャ > IOモジュールのputs関数(arity: 1) > Enum.each([1, 2], &IO.puts/1)

Keyword List> {key, val}なタプルのリスト > kw = [{:age, 3}, … ]

> mapっぽく書いてよい > kw == [age: 3, … ]

> Keyword.get(kw, :age) == 3

Keyword List> リストなので > 順序が保存される > ランダムアクセスは遅め

> キーが同じなら先頭側が優先されるKeyword.get([a: 1, a: 2], :a) == 1

Keyword List> configとして使われることが多い

> 引数として渡すとき > 最後の引数ならば [] 省略可Keyword.keys([a: 1, b: 2]) Keyword.keys(a: 1, b: 2)

紹介した型など> integer > float > atom > boolean > binary > string > list

> tuple > map > range > function > keyword list

制御構文

casecase the_number do 1 -> “one” 2 -> “two” 3 -> “three” end

ifif now == :morning do “good morning” else “hi” end

condcond do rem(y, 400) == 0 -> “Yes” rem(y, 100) == 0 -> “No” rem(y, 4) == 0 -> “Yes” true -> “No” end

無いもの> return > 最後の評価値が返る > loop, while > 再帰で

モジュールと関数

関数

defdefmodule MyModule do def print(arg) do iikanjini_hyoji(arg) end

defp iikanjini_hyoji(arg) do IO.inspect arg end end

MyModule.print %{price: 298}

原則> 全ての関数はモジュールに属する

> 名前か引数の数が違うなら別の関数 > add/2とsub/2は区別される > sum/1とsum/2は区別される

慣習> ワーカ関数の名前はdo_xxx > モジュール名とファイル構造は対応させる > lib/my_module/math.ex > MyModule.Math

> 最も関心のあるものを第一引数に > 例外を投げる関数の名前はxxx! > 真偽値を返す関数の名前はxxx?

デフォルト引数defmodule MyModule do def say(word \\ “hi”) do IO.puts word end end

MyModule.say(“hello”) MyModule.say

ディレクティブ

directivesdefmodule MyModule do import Enum

alias Enum, as: E

require Integer

use ExUnit end

importdefmodule MyModule do import Enum, only: [count: 1]

def kazoeru(list) do count(list) # Enum.count/1 end end

MyModule.kazoeru [1, 2, 3] MyModule.count [1, 2] → ❌

aliasdefmodule MyModule do alias Enum, as: E

def kazoeru(list) do E.count(list) # Enum.count/1 end end

MyModule.kazoeru [1, 2, 3]

as無しaliasdefmodule MyModule do alias Phoenix.HTML.Form alias Phoenix.HTML.Form, as: Form

# 等価 end

requireとuse

マクロが関係するのでまた後で…

構造体

定義defmodule User do defstruct name: “”, age: 0 end

> 初期値が全てnilならdefmodule User do defstruct [:name, :age] end

> 1モジュール1構造体

使用user = %User{} user = %User{name: "jack"} # 作成

user.name Map.get(user, :name) # 値の取得

# パターンマッチと更新 def hbd(user = %User{age: age}) do %User{user | age: age+1} end

ここまでのまとめ> defで関数を定義

> defmoduleでモジュールを定義

> 関数はモジュールの中で定義

> importで関数を取り込む

> aliasで別名をつける

> defstructで構造体を定義

パターンマッチと ガード式

パターンマッチ

賢く束縛> [x, y] = [1, 2] > x == 1 > y == 2

> {1, x, 3} = {1, 2, 3} > x == 2

アンスコ> 使わない変数の頭につける > 何にでもマッチ > 値は要らないとき

> [head | _] = [1, 2, 3] > {y, _m, _d} = {2015, 4, 30}

代表的な> {:ok, res} = File.read “a.txt”

> [head | tail] = [1, 2, 3, 4] > head == 1 > tail == [2, 3, 4]

スマートな

defmodule MyModule do def same?(x, x), do: true def same?(_x, _y), do: false end

実際的なcase File.read(“a.txt”) do {:ok, res} -> res {:error, :enoent} -> “oh it isn’t here” {:error, :eacces} -> “you can’t read it” _ -> “?” end

ピン止め> x = 1

> [x, y, 3] = [2, 2, 3] > x == 2, y == 2

> [^x, y, 3] = [2, 2, 3] > MatchError

↑ 再束縛されちゃってる

ガード式

defでdefmodule MyModule do def sum(list) when is_list(list) do # 略 end

def sum(_arg) do IO.puts "the arg must be a list" end end

caseで

case the_number do x when x in [1, 2, 3] -> IO.puts "small" _ -> IO.puts "big or negative" end

ガードで使える奴ら> == > != > === > !== > > > < > <= > >= > and > or > not > !

> + > - > * > / > <> (左辺がリテラル) > ++ (左辺がリテラル) > in > is_atom/1 > is_binary/1 > is_bitstring/1 > is_boolean/1 > is_float/1 > is_function/1

> is_function/2 > is_integer/1 > is_list/1 > is_map/1 > is_nil/1 > is_number/1 > is_pid/1 > is_port/1 > is_reference/1 > is_tuple/1 > abs/1 > bit_size/1 > byte_size/1

> div/2 > elem2 > hd/1 > length/1 > map_size/1 > node/0 > node/1 > rem/2 > round/1 > self/0 > tl/1 > trunc/1 > tuple_size/1

ここまでのまとめ>パターンマッチで賢く束縛

>要らない変数はアンスコで始める

> ピンで再束縛を防ぐ

> パターンマッチとガードを合わせて柔軟なマッチを

> ガードで使える関数は限られている

今回の内容> Elixirとは > 型と制御構文 > モジュールと関数 > パターンマッチとガード式