Episteme (Episteme v0.1.0)

Copy Markdown View Source

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

solution()

@type solution() :: %{optional(String.t()) => term()}

Functions

next_solution(stream, vars)

@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).

query(goal_term, db)

@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}.

query_lazy(goal_term, db)

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.

query_once(goal_term, db)

@spec query_once(term(), Episteme.Database.t()) ::
  {:ok, solution()} | :none | {:error, term()}

Like query/2, but returns only the first solution (or :none).