LoginSignup
12
4

More than 5 years have passed since last update.

Elixirで再帰呼び出しを使ってリストの加算関数をつくる

Last updated at Posted at 2018-06-25

(この記事は、「fukuoka.ex x ザキ研 Advent Calendar 2017」の8日目です)

昨日は@takasehidekiさんの「ElixirでIoT#1.3.2:プロセッサコアの動作周波数を揃えて比較評価してみた」でした.


はじめに

 前回の記事「Elixirのリストの仕様をまとめてみた」では,以下のようにリストの仕様をまとめました.

  • リストは先頭から操作すると速い
  • リストのループは再帰呼び出しでする

この記事では,Elixirで再帰呼び出しを使い,リストの操作を行う方法について説明します.

追記 2019/02/24

fukuoka.exではリストの操作(ループ)に再帰ではなく,Enum.map/reduceを推奨しています.

map/reduceメリット

読み進める方は上記のメリットを踏まえて,なお再帰呼び出しをしなければならないときに参考にしていただければと思います.

関数呼び出しの条件

Elixirでは,リストでなくとも,再帰呼び出しでループを行います.
詳細は,9 再帰 - Reccursionを参考にしてください. 
一般的な再帰呼び出しの例を示します.以下は,与えられた数の階乗を計算する関数です.

factorial.c
int factorial(int num){
  if(num > 1)
    return num * factorial(num-1); 
  else
    return 1;
};

次に,Elixirで記述した例を示します.

factorial.ex
defmodule Test do
  def factorial(num) when num > 1 do
    num * factorial(num-1)
  end
  def factorial(num), do: 1
end

(Elixirでは,関数が1文で済む場合は,do:を使って記述できます.後に空白が必要です.)
比較すると以下のような違いがあります.

  • if,elseのような制御文whenが関数名の後ろについている 
  • 関数が再定義,オーバーライドされているように見える

whenのように条件を指定,拡張するものをガード句といいます.これもパターンマッチングの1つとなります.呼び出す条件を変えた関数を複数定義し,呼び出すことで再帰呼び出しを行います.

上記のようにElixirでは,関数を定義する際に呼び出す条件を設定することができます.
条件を設定する方法としては,ガード句の他に引数にパターンマッチングを使用する方法があります.

引数のパターンマッチ

引数がリストであるなら,変数に[ ]をつける,hdhlを使うなどができるため,is_listのようなガード句は省略できます.一気に処理内容も書いてしまいます.

add.ex
defmodule Test do
  # 引数がリストである
  def add([a_hd | a_tl], [b_hd | b_tl]) do
    [ a_hd + b_hd | add(a_tl, b_tl) ]
  end
  # 引数がリストで,空である
  def add([], []), do:[]
end

引数にパターンマッチングを使用したことで,関数の中で(hd a)と書かずに引数として与えられたa_hdをそのまま使用できます.また,空リスト[ ]hdtlを使用するとエラーになりますので,add([],[])と呼び出した場合にも対応させています.

完成?

これでリストの加算関数が完成...ではありません.
まだ1次元リストにしか,対応していません.

iex
iex(1)> Test.add([1, 2, 3], [4, 5, 6])
[5, 7, 9]
iex(2)> Test.add([[1, 2], [3, 4]], [[5, 6], [7, 8]])
** (ArithmeticError) bad argument in arithmetic expression
    (test) lib/test.ex:29: Test.add/2

NumPy相当というからには最低でも2次元,できれば3次元にも対応したいところです.

2次元リストはガード句と合わせて,実装する必要があるため,次回の記事で扱いたいと思います.

まとめ

以上で,1次元リストの加算関数を実装しました.

要点をまとましょう.

  • Elixirでは,関数の呼び出し条件を設定できる
  • 関数の引数にもパターンマッチングを使用できる

明日は @Takeshi-Kogu さんの「Elixirでファイルの入出力をしてみた」 です。お楽しみに!

12
4
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
12
4