読者です 読者をやめる 読者になる 読者になる

技術のメモ帳

気が向いたときに書いてます

elixir学習日誌: 関数

基本

defmodule Say do
  def hello name do
    "Hello, #{name}!"
  end
end

IO.puts Say.hello "Alice" # => "Hello, Alice!"
  • defmodule関数をグループ化するためのモジュール定義
  • すべての関数は、モジュール名.関数名 引数 で呼び出せる。
  • 関数の呼び出しには () が付けられるが、ミミックメソッドの書式も可。

関数のスコープ

defmodule Say do
  defp bye name do
    "Bye, #{name}..."
  end
end

IO.puts Say.bye "Bob" # => UndefinedFunctionError
  • defpはモジュールの外からは呼び出せない。
  • defAPIを定義し、defpは内部実装を定義する。

ガード節

defmodule School do
  def classmate?(name) when name in ["Alice", "Bob"] do
    true
  end
end

School.classmate? "Alice"   # => true
School.classmate? "Charles" # => FunctionClauseError
  • 関数が呼び出される時点で、条件分岐を行う。
  • falseの場合の関数も定義する必要がある(例外が発生するため)。

引数のデフォルト値

defmodule Say do
  def hello name \\ "Alice" do
    "Hello, #{name}!"
  end
end

Say.hello # => "Hello, Alice"
  • \\ で区切るとデフォルト値が指定できる。

無名関数

greeting = fn name -> "How are you, #{name}?" end
greeting.("Alice") # => "How are you, Alice?"
  • fn(args) ->で無名関数が定義できる。
  • 名前付き関数との使い分けは、使い捨てにできるか否か

標準ライブラリ Enum

関数型言語なので、Enumを巧みに扱うことが求められる。

TODO: empty? sort reverse uniq with_index flat_map zip

Enum.map [1, 2, 3, 5, 8], fn(x) -> x*x end                   # => [1, 4, 9, 25, 64]
Enum.reduce [1, 2, 3, 4, 5], 0, fn(x, sum) -> sum + x end    # => 15
Enum.filter [:foo, :bar, :baz], fn(name) -> name == :foo end # => [:foo]
Enum.reject [:foo, :bar, :baz], fn(name) -> name == :foo end # => [:bar, :baz]
Enum.find [1, 2, 3], fn(x) -> x == 2 end                     # => 2
Enum.join [1, 2, 3], ","                                     # => "1,2,3"
Enum.each [1, 2, 3], fn(x) -> IO.puts x end                  # => 1 2 3
Enum.empty? []                                               # => true
Enum.sort [1, 2, 3], fn(a, b) -> a > b end                   # => [3, 2, 1]
Enum.reverse [1, 2, 3]                                       # => [3, 2, 1]
Enum.uniq [1, 1, 2]                                          # => [1, 2]
Enum.with_index [1, 2, 3]                                    # => [{1, 0}, {2, 1}, {3, 2}]
Enum.flat_map [[1, 2], [3, 4]], fn(x) -> x end               # => [1, 2, 3, 4]
Enum.zip [:foo, :bar], [1, 2]                                # => [foo: 1, bar: 2]

Ruby訳は以下となります。普段使っているメソッドと同じなので、かなり覚えやすいです。

[1, 2, 3, 5, 8].map {|x| x*x }
[1, 2, 3, 4, 5].reduce(0) {|sum, x| sum + x }
[:foo, :bar, :baz].select {|name| name == :foo }
[:foo, :bar, :baz].reject {|name| name == :foo }
[1, 2, 3].find {|x| x == 2 }
[1, 2, 3].join(",")
[1, 2, 3].each {|x| puts x }
[].empty?
[1, 2, 3].sort {|a, b| b <=> a }
[1, 2, 3].reverse
[1, 1, 2].uniq
[1, 2, 3].map.with_index {|x, i| [x, i] }
[[1, 2], [3, 4]].flat_map {|x| x }
[:a, :b].zip([1, 2])

参考

Part13:関数 | μ'sと学ぶソフトウェア開発入門

qiita.com

もっとEnumを知りたい場合は下記がいい感じ。all?やany?なんてメソッドもある。

http://elixir-lang.org/docs/v1.0/elixir/Enum.html