lib/wongi/engine.ex

defmodule Wongi.Engine do
  @moduledoc """
  A forward-chaining inference engine for Elixir.

  A port of the Ruby library with the same name.
  """

  alias Wongi.Engine.Entity
  alias Wongi.Engine.Rete

  @type t() :: Rete.t()
  @type fact() :: {any(), any(), any()} | Wongi.Engine.WME.t()
  @type template() :: {any(), any(), any()} | Wongi.Engine.WME.t()
  @type rule() :: Wongi.Engine.DSL.Rule.t()

  @doc """
  Creates a new engine instance.
  """
  @spec new() :: t()
  defdelegate new(), to: Rete

  @doc """
  Returns an engine with the given rule installed.

  See `Wongi.Engine.DSL` for details on the rule definition DSL.
  """
  @spec compile(t(), rule()) :: t()
  defdelegate compile(rete, rule), to: Rete

  @doc """
  Returns an engine with the given rule installed and the rule reference.

  The rule reference can be used to retrieve production tokens using `tokens/2`.

  See `Wongi.Engine.DSL` for details on the rule definition DSL.
  """
  @spec compile_and_get_ref(t(), rule()) :: {t(), reference()}
  defdelegate compile_and_get_ref(rete, rule), to: Rete

  @doc "Returns an engine with the given fact added to the working memory."
  @spec assert(t(), fact()) :: t()
  defdelegate assert(rete, fact), to: Rete

  @doc "Returns an engine with the given fact added to the working memory."
  @spec assert(t(), any(), any(), any()) :: t()
  defdelegate assert(rete, subject, predicate, object), to: Rete

  @doc "Returns an engine with the given fact removed from the working memory."
  @spec retract(t(), fact()) :: t()
  defdelegate retract(rete, fact), to: Rete

  @doc "Returns an engine with the given fact removed from the working memory."
  @spec retract(t(), any(), any(), any()) :: t()
  defdelegate retract(rete, subject, object, predicate), to: Rete

  @doc "Returns a set of all facts matching the given template."
  @spec select(t(), template()) :: MapSet.t()
  defdelegate select(rete, template), to: Rete

  @doc "Returns a set of all facts matching the given template."
  @spec select(t(), any(), any(), any()) :: MapSet.t()
  defdelegate select(rete, subject, predicate, object), to: Rete

  @doc "Returns a set of all tokens for the given production node reference."
  defdelegate tokens(rete, node), to: Rete
  @doc "Returns all production node references."
  defdelegate productions(rete), to: Rete

  def entity(rete, subject), do: Entity.new(rete, subject)
end