Keyword Predicates¶
Keyword predicates let you work with named fields in terms — inspecting which fields are bound, copying terms with overrides, and reflecting on predicate signatures. They use Python's native keyword argument syntax.
Quick Example¶
Partial Terms & Keyword Syntax¶
when you call a predicate with fewer arguments than it has fields, missing fields are filled with fresh logic variables (partial terms):
from my_module import point
p = point(x=10) # point(10, Var(), Var())
p = point(y=20, z=30) # point(Var(), 20, 30)
This is Python's native keyword syntax — no special Clausal syntax needed. See Syntax for the full language reference.
Predicates¶
vary/3¶
vary(Overrides, Term, NewTerm) — copy a term, replacing specified fields with
new values. Overrides is a Python dict mapping field names to new values.
Test("change one field") <- (
vary({"x": 100}, point(1, 2, 3), R),
R == point(100, 2, 3)
) # nv
Test("change multiple") <- (
vary({"x": 10, "z": 30}, point(1, 2, 3), R),
R == point(10, 2, 30)
) # nv
Works for both predicate-class terms and KWTerms.
extend/3¶
extend(Additions, Term, NewTerm) — copy a KWTerm with additional fields.
Only works with open-world KWTerms (not fixed-schema predicate classes).
Raises an error if you try to override an existing key — use vary for that.
unbound_keys/2¶
unbound_keys(Term, Keys) — list the field names that are still unbound
(contain logic variables).
Test("unbound") <- (
unbound_keys(point(1, Y, Z), KEYS),
in_("y", KEYS),
in_("z", KEYS),
length(KEYS, 2)
) # nv
Test("fully bound") <- unbound_keys(point(1, 2, 3), []) # nv
signature/3¶
signature(FunctorName, Arity, Names) — reflect the registered signature of a
predicate. Given a functor name and arity, unifies Names with the tuple of
field names.
This is a database-dependent operation — the predicate must have been defined
(with a signature) before signature is called.
Patterns & Recipes¶
Default values via vary¶
Inspect which fields need filling¶
Reflect on predicate structure¶
describe_predicate(NAME, ARITY) <- (
signature(NAME, ARITY, FIELD_NAMES),
writeln(f"Predicate {NAME}/{ARITY}"),
writeln(f"Fields: {FIELD_NAMES}")
)
Gotchas¶
extendis for KWTerms only — predicate classes have fixed schemas and cannot grow new fields. Usevaryto change existing fields.extenddoes not override — it raises an error if a key already exists. Usevaryfor updates.signaturerequires the predicate to be registered — if you call it before the predicate is defined (e.g., in a different module that hasn't been imported), it will fail.- Field names are strings — override dicts use string keys like
{"x": 10}, not variable names.
See also: Predicates — defining predicate structures, Term Inspection — functor, arg, unpack for generic term analysis, Dicts & Sets — DictTerm for general key-value data.