-
-
Notifications
You must be signed in to change notification settings - Fork 0
rules native
Predicates that bridge yopl unification to JS-native built-in types — Array, Map, Set, Date. Kept separate from rules-system so the latter stays focused on generic logic-programming primitives.
See dev-docs/native-objects.md for the full design and roadmap (what's shipped vs postponed).
import {rules as nativeRules} from 'yopl/rules/native.js'; // Compose with the rest of the library: import {rules as systemRules} from 'yopl/rules/system.js'; const rules = {...systemRules, ...nativeRules};
| Predicate | Succeeds when |
|---|---|
isArray(X) |
X is bound and is a JS Array |
isMap(X) |
X is bound and is a Map instance |
isSet(X) |
X is bound and is a Set instance |
isDate(X) |
X is bound and is a Date instance |
All four require their argument to be bound; otherwise they fail.
solve(rules, 'isArray', [[1, 2]], () => console.log('array')); solve(rules, 'isMap', [new Map()], () => console.log('map'));
Bind whichever side is unbound. Both bound → structural unification. Both unbound → fail.
const L = variable('L'); solve(rules, 'arrayList', [[1, 2, 3], L], env => assemble(L, env)); // → {value: 1, next: {value: 2, next: {value: 3, next: null}}} const A = variable('A'); solve(rules, 'arrayList', [A, makeList([10, 20])], env => assemble(A, env)); // → [10, 20]
The list-to-array direction fails on improper lists (non-null, non-cons tail) and on lists with unbound-Variable tails (open lists).
A and I must be bound; I must be a non-negative integer in range. Out-of-bounds fails. With X also bound, behaves as a check.
const X = variable('X'); solve(rules, 'arrayGet', [[10, 20, 30], 1, X], env => assemble(X, env)); // → 20 solve(rules, 'arrayGet', [[10, 20, 30], 0, 10], () => console.log('match')); // → match
A, I, X bound; A2 is a new array [...A] with A2[I] = X. I may be in-bounds (replace) or exactly A.length (append-at-end); larger or negative I is rejected to prevent silent hole creation.
The original array is not mutated.
const Out = variable('Out'); solve(rules, 'arraySet', [[10, 20, 30], 1, 99, Out], env => assemble(Out, env)); // → [10, 99, 30]
For multiple overrides, chain calls or build the new array inside a Js body goal.
A bound → N binds to A.length. Reverse mode (build an array of N holes) is intentionally unsupported.
Bind whichever side is unbound. When Es is bound, the entries are materialized into a Map and unified against M as Maps (order-independent). When only M is bound, entries emit in M's insertion order.
const Es = variable('Es'); const m = new Map([ ['a', 1], ['b', 2] ]); solve(rules, 'mapEntries', [m, Es], env => assemble(Es, env)); // → cons-list of [['a', 1], ['b', 2]]
M and K must be bound; V binds to M.get(K) if K ∈ M. Reverse-mode (find K from V) is non-deterministic in JS Maps and not supported.
Both M and K must be bound.
Same shape as mapEntries. When Items is bound, builds a Set and unifies as Sets (order-independent).
Both S and X must be bound.
Component bag C is a JS object with optional fields:
{year?, month?, day?, hour?, minute?, second?, ms?}
Month is 0-based (matching JS Date.prototype.getMonth). When constructing, missing fields default to 1970/0/1/0/0/0/0.
TZ-agnostic. D bound → Ms = D.getTime(). Ms bound → D = new Date(Ms).
D bound → C is filled with the local-time components. C bound → D = new Date(year, month, day, ...) constructed from local-time components.
const Y = variable('Y'), M = variable('M'); const d = new Date(2026, 4, 9); // May 9 2026 local solve(rules, 'dateComponents', [d, {year: Y, month: M}], env => { console.log(assemble(Y, env), assemble(M, env)); // 2026 4 });
Same as dateComponents but uses getUTCFullYear / getUTCMonth / ... and Date.UTC(...). Recommended default for logic programs that should produce TZ-independent answers.
The component bag is partial — only the fields you care about. Combined with the Lit-walker, partial-bag pattern matching is declarative:
import {rule, clause} from 'yopl/compile/clause/index.js'; import {Lit, Var} from 'yopl/compile/ir.js'; import {lowerRules} from 'yopl/compile/lower.js'; const myRules = lowerRules([rule('extractYear', 2)(clause`(D, Y) :- dateComponentsUTC(D, ${Lit({year: Var('Y')})})`)]);
- Home — module overview.
- rules-system — generic logic primitives.
-
compile-overview — the rule compiler and
Lit-walker.