lib/store.ex

defmodule Mimi.Store do
  @moduledoc """
  An `Agent` backend for memoization.
  """

  use Agent

  @doc """
  Start the Agent process and initialize with an empty map.
  """
  def start_link(), do: Agent.start_link(fn -> %{} end)

  @doc """
  Get a value associated with the given `key` or add and return the result of
  `fun.()` if the key isn't present.
  """
  def get_or_put(pid, key, fun) do
    case Agent.get(pid, &Map.fetch(&1, key)) do
      {:ok, value} ->
        value

      :error ->
        value = fun.()
        Agent.update(pid, &Map.put(&1, key, value))
        value
    end
  end
end