アルパカログ

カスタマーサポート (CS) とエンジニアリングを掛け算したい CRE (Customer Reliability Engineer) が気になる技術や思ったことなど。

【Elixir】再帰の書き方メモ

Elixir は再帰がすっきり書けてとても気持ちがいいですね。

でも、たましか書かないとすぐに書き方を忘れてしまうのでメモしておきます。

下記の例はページングのある API 再帰的に呼び出すケース。

defmodule MyAPIClient do
  use HTTPotion.Base
  use MockHTTPClient

  def process_response_body(body) do
    body |> Poison.decode!
  end

  def paginate(%HTTPotion.Response{status_code: 200, body: %{"users" => users, "next_url" => nil}}), do: users
  def paginate(%HTTPotion.Response{status_code: 200, body: %{"users" => users, "next_url" => next_url}}) do
    [users | paginate(MyAPIClient.get(next_url))]
  end
end

users = MyAPIClient.get("users") |> MyAPIClient.paginate
IO.inspect users

paginate 関数が再帰になっていて、API レスポンスの next_urlnil でない限りは下の paginate が呼び出されます。

API の結果である users を連結して返しますが、 next_urlnil になるまでは再帰的に呼び出される。

next_urlnil になると上の paginate が呼ばれ users を返して再帰が終了します。

リクエストは以前紹介した MockModule でモックしていています。

defmodule MockHTTPClient do
  @moduledoc """
  dev, testでHTTPotionによる外部HTTPリクエストをmockするmodule
  """

  @doc """
  HTTPotion.request/3 をoverrideしてdummy_responseを返します。
  """
  defmacro __using__(_) do
    quote do
      def request(method, url, options \\ []) do
        _dummy_response(method, url, options)
      end

      def _dummy_response(method, url, option) do
        %HTTPotion.Response{
          status_code: 200,
          headers: %HTTPotion.Headers{hdrs: []},
          body: _dummy_response_body(method, url, option) |> process_response_body
        }
      end

      def _dummy_response_body(:get, "users", []) do
        %{
          users: [
            %{
              id: 1,
              name: "xxx"
            }
          ],
          next_url: "users?page=2"
        } |> Poison.encode!
      end

      def _dummy_response_body(:get, "users?page=2", []) do
        %{
          users: [
            %{
              id: 2,
              name: "yyy"
            }
          ],
          next_url: nil
        } |> Poison.encode!
      end
    end
  end
end

list とスカラーの両方を再帰的に受け取る関数が書けるのも Elixir の楽しいところですよね。

ぜひいろんな再帰を書いて遊んでみてください。

こちらもあわせて読みたい

alpacat.hatenablog.com