-
-
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'));
// → matchA, 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.js';
import {Lit, Var, lowerRules} from 'yopl/compile';
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.