# Episteme v0.1.0 - Table of Contents

> A standalone Prolog-like resolution engine and clause database for Elixir: terms, unification, SLD-resolution, backtracking, a genuine clause-scoped cut, and builtin predicates, built on Ichor's search substrate. No parser -- bring your own front-end (e.g. Aletheia) or build goal terms directly.

## Pages

- [Episteme](readme.md)
- [Tutorial](tutorial.md)
- [Reference](reference.md)
- [Examples](examples.md)
- [Cheatsheet](cheatsheet.md)
- [Changelog](changelog.md)
- [Contributing](contributing.md)
- [LICENSE](license.md)

## Modules

- Top-level API
  - [Episteme](Episteme.md): 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.

- Term &amp; Database
  - [Episteme.Database](Episteme.Database.md): Clause storage: `{name, arity} -> ordered list of {head, body}`
clauses, `body` a single term (`true` for a fact, matching real
Prolog's own internal `Head :- Body` shape) -- looked up by
`Episteme.Engine` on every user-predicate call, and mutated in place by
`Episteme.Engine`'s `assert`/`asserta`/`assertz`/`retract`/`retractall`
dispatch. Populated either directly (`add_clause/2`/`add_fact/2`,
building terms yourself with `Episteme.Term`) or via `consult_forms/2`,
for any front-end that parses its own surface syntax into
`{:fact, _}`/`{:rule, _, _}` forms (Aletheia's reader is one such
front-end, but this module has no dependency on it or any particular
concrete syntax).
  - [Episteme.Term](Episteme.Term.md): Episteme's term representation: atoms and numbers are plain Elixir
atoms/integers/floats, lists are native Elixir lists, variables and
compounds get dedicated structs. This module is the
`Ichor.Backtrack.Term` implementation passed explicitly to every
`Ichor.Backtrack.Bindings` call, plus the handful of whole-term
operations (deep resolve, rename-apart) built on
`Ichor.Toolkit.TermWalk` that unification itself doesn't need but the
engine does.

  - [Episteme.Term.Compound](Episteme.Term.Compound.md): A compound term `name(args...)`.
  - [Episteme.Term.Var](Episteme.Term.Var.md): A logic variable: `ref` is its identity, `name` is display-only.

- Database Backends
  - [Episteme.Database.Backend](Episteme.Database.Backend.md): The storage contract `Episteme.Database` delegates every clause-storage
operation to, so the database's actual persistence strategy is a
pluggable choice rather than baked into `Episteme.Database` itself.
Ships two implementations -- `Episteme.Database.Backends.Ets` (the
default: an in-memory ETS table, indexed by `{name, arity}`) and
`Episteme.Database.Backends.Dets` (the same shape, backed by a DETS
file on disk, for a database that should survive past the owning
process) -- and any third module implementing this behaviour works
too: pass it as `Episteme.Database.new/1`'s `:backend` option.
  - [Episteme.Database.Backends.Dets](Episteme.Database.Backends.Dets.md): An on-disk `Episteme.Database.Backend`, for a database that should
survive past the owning process (or the VM) -- same `{name, arity}`-keyed
`:set` shape as `Episteme.Database.Backends.Ets`, backed by `:dets`
instead. Requires a `:file` option (a binary or charlist path) on
`Episteme.Database.new/1`; `:table` names the DETS table itself
(defaults to a name derived from `:file`, so two databases opened
against different files don't collide).
  - [Episteme.Database.Backends.Ets](Episteme.Database.Backends.Ets.md): The default `Episteme.Database.Backend`: an in-memory `:ets` `:set`
table keyed by `{name, arity}`, each row's value the predicate's own
clause list -- so clause order (what backtracking order depends on) is
exactly that Elixir list's order, never ETS's own unspecified
multi-row traversal order. `:public` access, so any process holding
the same `Episteme.Database.t()` value can read and mutate it, not
just the process that called `init/1` -- there is no coordination
beyond what `:ets` itself serializes, so concurrent `assert`/`retract`
against the *same predicate* from multiple processes can race (a
read-modify-write on one row); concurrent access to *different*
predicates never conflicts.

- Engine
  - [Episteme.Engine](Episteme.Engine.md): SLD-resolution over `Ichor.Backtrack.Tree` + `Ichor.Backtrack.Bindings`
plus `Episteme.Database` -- clause selection is `disjunction/2` folded
over a predicate's clauses in declared order, subgoal sequencing is
`conjunction/2`, both reused unmodified from Ichor. Control constructs
(`and`, `or`, `if_then`/`if_then_else`, `cut`, `not/1`, `call/N`,
`once/1`) live directly here rather than in a separate builtins
module: they turned out, once actually implemented, to be inseparable
from the cut-barrier machinery below, not independent predicates
dispatchable through a generic table. Every one of these is a plain
English name, not the traditional Prolog operator (`,`/`;`/`->`/`!`/
`\+`) it corresponds to -- Episteme has no reader of its own (see
`Episteme`'s moduledoc), so there's no textual syntax for any of this
to look "conventional" against; a word you can actually remember beat
matching ISO Prolog's punctuation.

- Builtins
  - [Episteme.Builtins.Arithmetic](Episteme.Builtins.Arithmetic.md): Evaluates a Prolog arithmetic expression term to an Elixir number
under `bindings` -- `is/2`'s own right-hand side, and both sides of
every arithmetic comparison (`numeric_equal/2`, `</2`, ...). Raises (via
`Episteme.Builtins.Exceptions.prolog_throw/1`) a standard `type_error`
for anything that isn't a number, a bound variable, or a recognized
evaluable functor.
  - [Episteme.Builtins.Exceptions](Episteme.Builtins.Exceptions.md): Standard ISO error-term constructors (`type_error/2`, `domain_error/2`,
`instantiation_error/1`) plus the raw Elixir `throw` tag Episteme's own
`throw/1`/`catch/3` (in `Episteme.Engine`, which needs to `solve` the
recovery goal) and every builtin that detects bad input raise through.
  - [Episteme.Builtins.Io](Episteme.Builtins.Io.md): Minimal I/O: `write/1 writeln/1 print/1 nl/0` -- canonical
`functor(args)` text via `Episteme.Term.to_text/1` (no operator-aware
pretty-printing yet). Each succeeds exactly once, side effect aside.

  - [Episteme.Builtins.Lists](Episteme.Builtins.Lists.md): The list predicate family -- `length/2 append/3 member/2 reverse/2
nth0/3 nth1/3 last/2` -- over native Elixir lists (Episteme lists are
plain `[h|t]`, not cons compounds). Hand-rolled-goal style,
generalized to real unification via `Ichor.Backtrack.Bindings`.

