 
   @callback exception(term) :: t
   @callback message(t) :: String.t()
+
+  @doc """
+  Called from `Exception.blame/3` to augment the exception struct.
+
+  Can be used to collect additional information about the exception
+  or do some additional expensive computation.
+  """
+  @callback blame(t, stacktrace) :: {t, stacktrace}
+  @optional_callbacks [blame: 2]
 
   @doc """
   Returns `true` if the given `term` is an exception.

    ""
  end

  def blame(
        %{
          module: module,
          function: function,
          arity: arity,
          kind: kind,
          args: args,
          clauses: clauses
        },
        inspect_fun,
        ast_fun
      ) do
    mfa = Exception.format_mfa(module, function, arity)

    formatted_args =


  This operation is potentially expensive, as it reads data
  from the filesystem, parse beam files, evaluates code and
  so on.

  If the exception module implements the optional `c:blame/2`
  callbak, it will be invoked to perform the computation.
  """
  @spec blame(:error, any, stacktrace) :: {t, stacktrace}
  @spec blame(non_error_kind, payload, stacktrace) :: {payload, stacktrace} when payload: var
  def blame(kind, error, stacktrace)

  def blame(:error, error, stacktrace) do
    %module{} = struct = normalize(:error, error, stacktrace)

    if Code.ensure_loaded?(module) and function_exported?(module, :blame, 2) do
      module.blame(struct, stacktrace)
    else
      {struct, stacktrace}
    end
  end

  def blame(_kind, reason, stacktrace) do
    {reason, stacktrace}
  end

  @doc """
