Top-level API for querying an already-built Episteme.Database:
query/2 solves a goal term against one, returning every solution's
variable bindings. No parser lives here -- a goal is always an
already-built term (Episteme.Term.new_var/1, %Episteme.Term.Compound{},
plain Elixir atoms/numbers/lists), and a database is built directly via
Episteme.Database.add_clause/2/add_fact/2, or via consult_forms/2
for a front-end that parses its own surface syntax into
{:fact, _}/{:rule, _, _} forms. Aletheia's reader is one such
front-end, built on top of this library; this library has no
dependency on it or on any particular concrete syntax.
Uncaught Prolog exceptions (a real throw/1 no catch/3 in the
program itself caught) surface as {:error, term} here, at the
outermost boundary, rather than as a raw Elixir throw escaping to
the caller.
Summary
Functions
Pulls one solution from a query_lazy/2 stream: {:solution, bindings, rest}, :none when exhausted, or {:error, term} for an uncaught
Prolog exception raised while solving this solution (each pull is
independently guarded, since a lazy caller may pull solutions across
arbitrarily many separate calls, unlike query/2's one eager pass).
Solves goal against db, returning every solution's variable
bindings as %{name => term} maps (Episteme.Term.to_text/1-ready
values, already fully resolved). A real Prolog throw/1 that escapes
uncaught surfaces as {:error, term}.
Like query/2, but doesn't force every solution eagerly -- returns the
raw lazy solution stream plus the goal's own named variables, both
meant to be passed straight to next_solution/2. For a REPL (or any
caller that only wants the first few solutions of a possibly-infinite
search) instead of query/2's own "pull the whole list" behavior.
Like query/2, but returns only the first solution (or :none).
Types
Functions
@spec next_solution(Ichor.Backtrack.Tree.t(), MapSet.t(Episteme.Term.Var.t())) :: {:solution, solution(), Ichor.Backtrack.Tree.t()} | :none | {:error, term()}
Pulls one solution from a query_lazy/2 stream: {:solution, bindings, rest}, :none when exhausted, or {:error, term} for an uncaught
Prolog exception raised while solving this solution (each pull is
independently guarded, since a lazy caller may pull solutions across
arbitrarily many separate calls, unlike query/2's one eager pass).
@spec query(term(), Episteme.Database.t()) :: {:ok, [solution()]} | {:error, term()}
Solves goal against db, returning every solution's variable
bindings as %{name => term} maps (Episteme.Term.to_text/1-ready
values, already fully resolved). A real Prolog throw/1 that escapes
uncaught surfaces as {:error, term}.
@spec query_lazy(term(), Episteme.Database.t()) :: {Ichor.Backtrack.Tree.t(), MapSet.t(Episteme.Term.Var.t())}
Like query/2, but doesn't force every solution eagerly -- returns the
raw lazy solution stream plus the goal's own named variables, both
meant to be passed straight to next_solution/2. For a REPL (or any
caller that only wants the first few solutions of a possibly-infinite
search) instead of query/2's own "pull the whole list" behavior.
@spec query_once(term(), Episteme.Database.t()) :: {:ok, solution()} | :none | {:error, term()}
Like query/2, but returns only the first solution (or :none).