Libraries¶
A Library bundles operators, clauses, primitives and functions into a named, loadable unit a Solver can use.
Multiple libraries can be loaded at once, grouped into a Runtime.
Pluggable¶
Library extends Pluggable (it.unibo.tuprolog.solve.library), which defines what a library actually contributes:
/**
* Base type for anything that can be "plugged into" a solver by contributing operators, clauses, primitives, and
* functions -- namely [Library] and [Runtime] (a group of libraries), which both implement this by aggregating
* their constituents' contributions.
*/
interface Pluggable {
/** Operators to be loaded by a solver when the library is used */
@JsName("operators")
val operators: OperatorSet
/** Rules, facts, or directories to be loaded by a solver when the library is used */
@JsName("clauses")
val clauses: List<Clause>
/** [Primitive]s to be loaded by a solver when the library is used,
* indexed by their [Signature] in the eyes of the solver */
@JsName("primitives")
val primitives: Map<Signature, Primitive>
operators: OperatorSet— operators to register with the solver;clauses: List<Clause>— facts/rules/directives to load into the theory (see Default predicates for an example);primitives: Map<Signature, Primitive>andfunctions: Map<Signature, LogicFunction>— see Primitives and functions.
Pluggable also provides default lookup helpers: contains(signature), contains(operator), hasPrimitive,
hasFunction, hasRule, rulesSignatures (derived from clauses), and hasProtected (signatures a library
reserves — PrimitiveWrapper's permission checks consult this, see
Errors and exceptions).
Library¶
* Bundling all four kinds of extension together, rather than exposing four separate registration points on
* [it.unibo.tuprolog.solve.Solver], is what makes it possible to ship a self-contained feature (e.g. `:io-lib`,
* `:oop-lib`) as a single pluggable unit. Since more than one [Library] can be loaded into a `Runtime` at once,
* [alias] is what lets clashing predicate indicators between libraries be resolved without either library needing
* to know about the other (see [of] and its `alias` parameter).
*
* @see Runtime
* @see it.unibo.tuprolog.solve.libraryOf
* */
interface Library : Pluggable {
The only addition over Pluggable is alias: String — the name a solver uses to refer to the library, following
the pattern \w+(\.\w+)* (segments separated by Library.ALIAS_SEPARATOR, i.e. "."). Aliasing lets a solver
disambiguate predicates with clashing signatures across libraries by qualifying them, e.g. prolog.lang:is/2.
Instances are built through the companion factories, not by implementing the interface directly:
Library.of(alias, primitives, clauses, operators, functions)— full form (all collections default to empty);Library.of(primitives, clauses, operators, functions)— same, aliased"default";Library.of(alias, library)— re-aliases an existingLibrary.
CommonBuiltins (see Default predicates) is the running example: an AbstractLibrary
object aliased "prolog.lang", whose clauses/primitives/functions delegate to CommonRules/CommonPrimitives/
CommonFunctions respectively. AbstractLibrary and AbstractPluggable supply sensible defaults (empty
collections, equals/hashCode/toString based on alias + contents) so a custom library only needs to override
what it actually provides. LibraryImpl is the concrete class backing Library.of(...); ExtensionLibrary wraps
another Library while overriding only some of its members.
Runtime¶
A Runtime is an immutable, alias-indexed group of Library instances — what a Solver's libraries property
holds (see Solver API):
* Represents a group of [Library] objects constituting the runtime a logic solver may leverage upon, keyed by
* [Library.alias] (as the underlying `Map<String, Library>` reflects).
*
* A [it.unibo.tuprolog.solve.Solver] loads exactly one [Runtime] (see [it.unibo.tuprolog.solve.SolverFactory.defaultRuntime]);
* `Runtime` is what lets several independently-authored [Library] instances (e.g. `:io-lib`, `:oop-lib`, a
* standard-library `Library`) coexist within a single solver, aliasing being the mechanism that resolves clashing
* predicate indicators without either library needing to know about the other.
*
* Construct one via the companion's [empty]/[of] factories, or combine [Library]/[Runtime] instances with [plus].
*
* @see Library
* @see it.unibo.tuprolog.solve.MutableSolver.setRuntime
*/
interface Runtime :
Pluggable,
Map<String, Library> {
/** The [Library.alias] of every library in this runtime; same as this map's [keys]. */
@JsName("aliases")
val aliases: Set<String>
/** All libraries composing this library group */
@JsName("libraries")
val libraries: Set<Library>
/** Merges every library's [Pluggable.clauses] into a single indexed [Theory], using [unificator]. */
@JsName("asTheory")
fun asTheory(unificator: Unificator): Theory
/**
* Returns a new [Runtime] with [other] added to [libraries].
* @throws it.unibo.tuprolog.solve.library.exception.AlreadyLoadedLibraryException if a library aliased as [other]'s [Library.alias] is already loaded.
*/
@JsName("plusLibrary")
operator fun plus(other: Library): Runtime
Runtime itself implements Pluggable (its operators/clauses/primitives/functions are the union of all
contained libraries') and Map<String, Library> (keyed by alias), plus:
aliases/libraries— the set of alias strings /Libraryinstances it contains;plus(library)/plus(runtime)— add one or more libraries;minus(library)/minus(alias)/minus(aliases)— remove libraries;update(library)— replace an already-loaded library (same alias) with a new version;asTheory(unificator)— flattens all libraries' clauses into a singleTheory.
Build one with Runtime.empty(), Runtime.of(vararg library), or Runtime.of(iterable/sequence).
Loading and unloading¶
Outside of a running resolution, MutableSolver (see Solver API) exposes
loadLibrary(library), unloadLibrary(library) and setRuntime(runtime) directly.
From within a primitive, the same effect is achieved declaratively, via the SideEffect.AlterRuntime family
attached to a Solve.Response — LoadLibrary, UnloadLibraries, UpdateLibrary, AddLibraries, ResetRuntime —
since a primitive cannot mutate the ExecutionContext it was given (see
Primitives and functions).
Library-related failures are reported as LibraryException (it.unibo.tuprolog.solve.library.exception, extending
TuPrologException directly rather than ResolutionException): NoSuchALibraryException and
AlreadyLoadedLibraryException.
See Solver design for why libraries — rather than a monolithic built-in set — are the unit of extension for the resolution engine.