Predicates and facts
A predicate is a named, typed relation. Declare it withpred, giving a type for each
column:
u32, u64, i32, i64, f32,
f64, bool, and symbol. Every fact must match its declaration; a value of the
wrong type is a compile-time error, caught before any kernel runs. You can also name
columns for readability:
symbol values are interned strings backed by dense integer IDs. They compare and
join as fast as integers, but XLOG remembers the original text and prints it back in
query output — so you get readable results without giving up integer performance.Rules
A rule derives new facts. It has a head (what it produces) and a body (the conditions), separated by:-, which reads as “if”:
reach(X, Y) holds whenever edge(X, Y) holds. Names beginning with an
uppercase letter are variables; names beginning with lowercase are predicate or
value names. The rule above copies every edge into reach.
Joins are shared variables
When a rule body has more than one atom, they are joined on the variables they share. To follow an edge and then another edge, mention the same variableY in both:
Y appears in both edge atoms, the engine
joins them where the destination of the first equals the source of the second — a hash
join, executed on the GPU. Variables that appear only once can be written as _, the
anonymous wildcard, when you do not need their value:
_ is a fresh, independent placeholder — two underscores in the same rule are not
required to match.
Querying results
A query asks the engine to compute and print a relation. Write it with?-:
Putting it together
reach rule refers to reach in its own body — that is recursion, and it
is where XLOG’s semi-naive fixpoint evaluation does its work.
Recursion
How recursive rules are evaluated to a fixpoint, and how to keep them terminating.