Package Exports
- yopl
- yopl/compile
- yopl/compile/clause
- yopl/compile/clause/index.d.ts
- yopl/compile/clause/index.js
- yopl/compile/index.d.ts
- yopl/compile/index.js
- yopl/compile/ir.d.ts
- yopl/compile/ir.js
- yopl/compile/lower.d.ts
- yopl/compile/lower.js
- yopl/compile/parse/body-expr.js
- yopl/compile/parse/cursor.js
- yopl/compile/parse/expr.js
- yopl/compile/parse/goal.js
- yopl/compile/parse/interp.js
- yopl/compile/parse/lexer.js
- yopl/compile/parse/op-table.js
- yopl/compile/parse/term.js
- yopl/compile/parse/util.js
- yopl/compile/prolog
- yopl/compile/prolog/clause.js
- yopl/compile/prolog/file
- yopl/compile/prolog/file.d.ts
- yopl/compile/prolog/file.js
- yopl/compile/prolog/index.d.ts
- yopl/compile/prolog/index.js
- yopl/compile/prolog/program.js
- yopl/compile/validate.d.ts
- yopl/compile/validate.js
- yopl/rules/bits.d.ts
- yopl/rules/bits.js
- yopl/rules/comp.d.ts
- yopl/rules/comp.js
- yopl/rules/logic.d.ts
- yopl/rules/logic.js
- yopl/rules/math.d.ts
- yopl/rules/math.js
- yopl/rules/native.d.ts
- yopl/rules/native.js
- yopl/rules/system-runtime.d.ts
- yopl/rules/system-runtime.js
- yopl/rules/system.d.ts
- yopl/rules/system.js
- yopl/solve.d.ts
- yopl/solve.js
- yopl/solvers/async.d.ts
- yopl/solvers/async.js
- yopl/solvers/asyncGen.d.ts
- yopl/solvers/asyncGen.js
- yopl/solvers/gen.d.ts
- yopl/solvers/gen.js
Readme
yopl 
yopl is an ES6 mini-library that implements a Prolog-style logic solver in JavaScript. It provides:
- A small core solver with multiple driver styles: callback, generator, async callback, async generator.
- A built-in rule library: helpers and control predicates, comparisons, arithmetic, bitwise, boolean logic, and JS-native bridges (Array / Map / Set / Date).
- A rule compiler with two tagged-template front-ends — a per-clause DSL (
clause\...`) and a strict-Prolog whole-program parser (prolog`...``) — write rules declaratively, catch arity drift at compile time.
Its only runtime dependency is deep6, itself a zero-dependency library that provides the unification engine.
What it does and when to use it
yopl lets you describe a problem as a set of rules over JavaScript values and ask the solver to find values that satisfy them. You write declarative rules; the engine handles search, unification, and backtracking. You stay inside JavaScript — there is no embedded DSL to parse, no separate Prolog runtime, and rules can call back into plain JS (sync or async) whenever a piece of logic is easier to express that way.
It is useful when a problem is awkward to express as straight-line code but natural to express as constraints or relations:
- Pattern matching and shape validation against deeply nested data, where you also want to extract values during the match.
- Searching configurations, dependency graphs, or rule sets for combinations that satisfy several conditions at once.
- Type-inference-like or tag-propagation passes over an AST or IR.
- Small expert systems, planners, permission/policy checks, and "find me an X such that Y" queries embedded inside a larger JS app.
- Test fixtures and property-style checks that need to enumerate all values matching a spec.
If you only need single-direction pattern matching, a regex or a destructuring assignment is simpler. Reach for yopl when you need bidirectional matching (unification), backtracking across alternative rules, or enumeration of all solutions — and you want all of that without leaving your JavaScript codebase.
Installation
npm install --save yoplQuick start
import {variable} from 'deep6/env.js';
import assemble from 'deep6/traverse/assemble.js';
import solve from 'yopl';
const rules = {
member: [(V, X) => [{args: [{value: V, next: X}, V]}], (V, X) => [{args: [{next: X}, V]}, {name: 'member', args: [X, V]}]]
};
const list = {value: 1, next: {value: 2, next: {value: 3, next: null}}};
const X = variable('X');
solve(rules, 'member', [list, X], env => {
console.log('X =', assemble(X, env));
});
// X = 1
// X = 2
// X = 3Modules
| Module | Purpose |
|---|---|
yopl (src/solve.js) |
Synchronous callback solver — main entry point. |
yopl/solvers/gen.js |
Synchronous generator solver. |
yopl/solvers/async.js |
Async callback solver. |
yopl/solvers/asyncGen.js |
Async generator solver. |
yopl/compile |
IR constructors (Var, Lit, Compound, …) + lowerRule/lowerRules + validate/validateOrThrow + IR symbol + deep6 re-exports. |
yopl/compile/clause |
Per-clause tagged-template DSL: rule(name, arity)(clause\...`)`. |
yopl/compile/prolog |
Strict-Prolog tagged-template parsers: prolog\...`, prologClause`...``. |
yopl/compile/prolog/file |
Filesystem-backed loaders: prologFile, prologFileAsync (Node / Bun / Deno). |
yopl/rules/system.js |
Generic logic primitives: helpers + eq, notEq, unifyOpts, not, map, filter, type tests, … |
yopl/rules/native.js |
JS-native bridges: Array / Map / Set / Date predicates + type tests (isArray, isMap, …). |
yopl/rules/comp.js |
Comparisons: lt, le, gt, ge, nz. |
yopl/rules/math.js |
Arithmetic: add, sub, mul, div, neg (each reversible); is/2 arithmetic-expression evaluator; =:=/=\= arithmetic comparison. |
yopl/rules/bits.js |
Bitwise: bitAnd, bitOr, bitXor, bitNot. |
yopl/rules/logic.js |
Boolean logic: logicalAnd, logicalOr, logicalXor, logicalNot. |
Per-module documentation lives in the wiki.
CommonJS
yopl ships as ESM only. CommonJS consumers can use Node's built-in dynamic import():
const {default: solve} = await import('yopl');A full CJS interop demo lives in tests/test-cjs.cjs (run it with node tests/test-cjs.cjs).
Development
git clone https://github.com/uhop/yopl.git
cd yopl
npm install
npm testSee CONTRIBUTING.md for the development workflow and AGENTS.md for AI-agent rules.
Release history
- 1.4.0 — strict-Prolog tagged-template parser, bugfixes, major perf improvements.
- 1.3.0 — rule compiler, JS-native predicate library (
Array/Map/Set/Date),unifyOpts/3. - 1.2.0 — removed CJS build, restructured tests, added TypeScript typings, simplified list creation, bug fixes and performance improvements, expanded docs and wiki.
- 1.1.4 — updated dependencies.
- 1.1.3 — updated dependencies.
- 1.1.2 — updated dependencies.
- 1.1.1 — updated dependencies.
- 1.1.0 — deep6 was extracted from this package and is now a dependency.
- 1.0.1 — added the
exportsstatement. - 1.0.0 — first 1.0 release.
The full release notes are in the wiki: Release notes.