8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 17

Elixirのチートシートを作ろう #11 関数その1

Last updated at Posted at 2024-12-16

1. OverView

ここまでの説名で、散々使っといて、今更、どの面下げて解説すりゃいいんでしょうねぇ。
と、思いつつ、書くことたくさんあるので、ここも随時分割していきたいと思います。

Elixir Schoolの説明順に問題があると考えて始めたこの企画ですが、うーん、昨今の言語だと
しかたないのかな、と言う気がしてきました。関数の使い方と引数である型を覚えないと、サンプル書いても
訳がわかんないんだよね。

2 まずは解説

2.1 匿名関数(Anonymous Functions)

匿名関数です。無名変数とも呼ばれます。

これ、ここまでの説明でも頻発しましたが、

fn (引数) -> 関数本体 end

と言う定義になります。

sum = fn (a, b) -> a + b end
sum.(2, 3)
5

そして、省略記法があります。

sum = &(&1 + &2)
sum.(2, 3)
5

省略記法では、引数は&1, &2と省略して書けます。
引数、シェル言語が?貴様?と思いますが、enum何かだと御世話になりますね。

iex(23)> Enum.map([0, 1, 2, 3], fn(x) -> x * 5 end)
[0, 5, 10, 15]
iex(24)>  Enum.map([0, 1, 2, 3], &(&1 * 5))
[0, 5, 10, 15]
iex(25)>

fn ~ endとくらい書けよ、みたいな話をおいておくと、ここでわざわざxと言う変数を定義せずに済むので
無駄に言いありげな変数名を乱発しないので、逆に可読性が上がると思います。

2.2 パターンマッチ

さて、Elixir Schoolを見てみましょう。

Elixirではパターンマッチは変数だけに限定されているわけではなく、次の項にあるように、関数へと適用することができます。
Elixirはパターンマッチを用いてマッチする可能性のある全てのオプションをチェックし、最初にマッチするオプションを選択して実行します:
handle_result = fn
  {:ok, result} -> IO.puts "Handling result..."
  {:ok, _} -> IO.puts "This would be never run as previous will be matched beforehand."
  {:error} -> IO.puts "An error has occurred!"
end

関数の引数で、それぞれ実行される本体が変わってくるんですね。
あー、これで、check_ok_with_resultとかcheck_errorとか引数ごとに別の関数を作らなくて済むと言ううれしい話。

iex(79)> handle_result.({:ok, some_result})
Handling result...
:ok
iex(81)> handle_result.({:error})
An error has occurred!
:ok

引数に合わせて、結果が変わっているのがわかるでしょうか?

2.3 名前付き関数

モジュールは次回やるので、今回はモジュールはおいておきます。
ざっと説明するとdefmoduleでモジュールを定義して、その中に関数を作ります。

defmodule Greeter do
  def hello(name) do
    "Hello, " <> name
  end
end

はい、def 関数名(引数) do ~ endですね。
この、関数名で、関数が呼び出せます。

Greeter.hello("Sean")
"Hello, Sean"

ついでに、
関数本体が1行で済むなら、 do: を使ってより短くすることができます:

defmodule Greeter do
  def hello(name), do: "Hello, " <> name
end

さて、ここまでコピペですが、ここでがっつり解説となります。

2.4 本日分だけでも、とっても再帰が簡単ですね。

defmodule Length do
  def of([]), do: 0
  def of([_ | tail]), do: 1 + of(tail)
end

さて、名前付きですが、パターンマッチ、関数本体が1行で済むなら、 do: を使ってより短くを使って、簡潔に
再帰処理をしております。

Lengthモジュールのofを、引数[]で呼び出し…

Length.of [1, 2, 3]
3

さて、関数の中身ですが、

  def of([]), do: 0 <-これは、終了処理です
  def of([_ | tail]), do: 1 + of(tail) これが、計算する本体

_ | tailは、以下の様にマッチします。

実行回数 関数の戻り値 説明
初回 1 tail(2,3) of(2,3)が、呼び出す
2回 2 tail(3) of(3)が、呼び出す
3回 3 tail(nil) of(nil)が呼び出す -> これが戻り値となる
4回目 3 引数がnilなので、加算せずに、do:0が実行される

以上の様に、再帰が非常に簡潔に書けます。
いやぁ、便利便利。いろんな記法を覚えた甲斐がありますな。
まぁ、実際にはEnumを使うんでしょうがね。

3. 本日のチートシート

関数名 説明
匿名関数(Anonymous Functions) fn (引数) -> 関数本体 endで定義する sum = fn (a, b) -> a + b end
sum.(2, 3)
5
匿名関数の省略記法 &()で関数を囲む、引数は&1,&2...となる sum = &(&1 + &2)
sum.(2, 3)
5
関数の引数のパターンマッチ パターンマッチは関数へと適用することが出来る handle_result = fn
{:ok, result} -> IO.puts "Handling result..."
{:ok, _} -> IO.puts "This would be never run as previous will be matched beforehand."
{:error} -> IO.puts "An error has occurred!"
end
名前付き関数 モジュールを定義し、その中に関数を作る defmodule Greeter do
def hello(name) do
"Hello, " <> name
end
end
関数本体が1行で済むなら、 do: を使ってより短くすることが出来る defmodule Greeter do
def hello(name), do: "Hello, " <> name
end
8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?