ヽ(´・肉・`)ノログ

How do we fighting without fighting?

Sapporo.beamした

2人もきてくれた.Elixirのことしかやってない.

今日話したところ.

iexでリファレンス読めるよ

# s Enum と打つと Enum の使える関数一覧が読める
s Enum
@spec all?(t()) :: boolean()
@spec all?(t(), (element() -> as_boolean(term()))) :: boolean()
(snip)
@spec with_index(t()) :: [{element(), non_neg_integer()}]

# h Enum.map と打つと Enum.map のリファレンスが読める
h Enum.map
                                      Enum

Provides a set of algorithms that enumerate over collections according to the
Enumerable protocol:

┃ iex> Enum.map([1, 2, 3], fn(x) -> x * 2 end)
┃ [2,4,6]

Some particular types, like dictionaries, yield a specific format on
enumeration. For dicts, the argument is always a { key, value } tuple:

┃ iex> dict = HashDict.new [a: 1, b: 2]
┃ iex> Enum.map(dict, fn { k, v } -> { k, v * 2 } end) |> Enum.sort
┃ [a: 2, b: 4]

Note that the functions in the Enum module are eager: they always start the
enumeration of the given collection. The Stream module allows lazy enumeration
of collections and provides infinite streams.

Since the majority of the functions in Enum enumerate the whole collection and
return a list as result, infinite streams need to be carefully used with such
functions, as they can potentially run forever. For example:

┃ Enum.each Stream.cycle([1,2,3]), &IO.puts(&1)

関数をアレする &

http://elixir-lang.org/getting_started/6.html の Function capture 参照

# &(&1) は fn(x) -> (x) end と同じ
Enum.map [1,2,3,4], fn(x) -> (x * 2) end # => [2, 4, 6, 8]
Enum.map [1,2,3,4], &(&1 * 2) # => [2, 4, 6, 8]

# &1 は複数回使うことができる
Enum.map [1,2,3,4], fn(x) -> (x * x) end # => [1, 4, 9, 16]
Enum.map [1,2,3,4], &(&1 * &1) # => [1, 4, 9, 16]

# 引数が複数あるなら &1, &2 と使える
Enum.sort [4,2,1,3], fn(x, y) -> (x < y) end # => [1, 2, 3, 4]
Enum.sort [4,2,1,3], &(&1 < &2) # => [1, 2, 3, 4]

# & を名前つき関数に使うこともできる
size("foo") # => 3
Enum.map ["foo", "bar", "baz"], fn(x) -> size(x) end # => [3, 3, 3]
Enum.map ["foo", "bar", "baz"], &size/1 # => [3, 3, 3]

# size/1 の /1 部分は引数の数を表している
# ElixirとErlangでは「名前/引数の数」で一つの関数を表す
# 引数が違ったら別の関数

パイプライン |>

Kernel.|>/2

# [1, [2], 3]
# の結果をフラットにする
# の結果を 2 倍する
[1, [2], 3] |> List.flatten |> Enum.map(&(&1 * 2)) # => [2, 4, 6]

パターンマッチ

# 要素をバラバラに変数へ束縛できる
[a, b, c] = [:a, "b", 3]
a # => :a
b # => "b"
c # => 3

# | を使って
# 最初の要素と,残りのリストにもできる
[head|tail] = [1, 2, 3, 4]
head #=> 1
tail #=> [2, 3, 4]

# 文字もパターンマッチできるよ
<<head::utf8, tail::binary>> = "abcdef"
head #=> 97
# これには事情がありまして……
# こんど説明する
<<head::utf8>> # => a
tail # => "bcdef"

# マルチバイト文字も行けるよ
<<head::utf8, tail:binary>> = "日本語"
<<head::utf8>> # => "日"
tail # => "本語"

<<ni::utf8, hon::utf8, go::utf8>> = "日本語"
<<ni::utf8>> # => "日"
<<hon::utf8>> # => "本"
<<go::utf8>> # => "語"

パターンマッチと関数定義を組み合わせる

defmodule MyModule do
  # 引数が 0 ならここにマッチする
  def zero?(0) do
    true
  end

  # 引数 x を is_number(x) して true ならここにマッチする
  def zero?(x) when is_number(x) do
    false
  end

  # それ以外は何もしない
end

MyModule.zero?(0)  #=> true
MyModule.zero?(1)  #=> false
MyModule.zero?([1,2,3])
** (FunctionClauseError) no function clause matching in MyModule.zero?/1
    iex:74: MyModule.zero?([1, 2, 3])
# MyModule.zero?/1 にはマッチしなかったわというエラー

宿題

このエントリーをはてなブックマークに追加