Rules
Rules are where the computation happens. Each rule says "if these conditions hold, derive these new facts."
Anatomy of a rule
A rule has a head (what to derive) and a body (the conditions), separated by :- and ending with a period:
Head(args...) :- body1, body2, ... .
The classic example — transitive closure:
.decl Arc(x: int32, y: int32)
.decl Tc(x: int32, y: int32)
// Base case: every arc is in the transitive closure
Tc(x, y) :- Arc(x, y).
// Recursive case: extend by one hop
Tc(x, y) :- Tc(x, z), Arc(z, y).
Atoms
An atom is a reference to a relation with arguments. Arguments can be variables, constants, or the _ placeholder:
Edge(x, y) // two variables
Edge(1, y) // constant + variable
Edge(_, y) // don't care about first column
Positive atoms
A positive atom in the body says "this tuple must exist":
Reach(y) :- Reach(x), Arc(x, y).
Both Reach(x) and Arc(x, y) are positive atoms. The shared variable x is a join key — FlowLog only matches rows where x has the same value in both relations.
Negative atoms
Prefix with ! to negate — "this tuple must not exist":
// Nodes with no outgoing edges
Isolated(x) :- Node(x), !Edge(x, _).
Joins
When a variable appears in multiple body atoms, it's a join. FlowLog keeps only the combinations where that variable matches:
// y joins Edge and Node — only matching pairs survive
Match(x, label) :- Edge(x, y), Node(y, label).
Join variables must have compatible types across all atoms they appear in.
Constants in rules
Integer, string, and boolean constants work anywhere — heads, bodies, you name it:
Edge(1, 2). // fact with integer constants
Name(1, "alice"). // string constant
Active(x) :- Flag(x, True). // boolean constant in body
Remember: boolean literals are capitalized (True, False).
Multiple rules
Multiple rules can derive facts for the same relation. The result is the union of everything derived:
.decl Reach(id: int32)
Reach(y) :- Source(y).
Reach(y) :- Reach(x), Arc(x, y).
Think of it as: each rule contributes rows, and FlowLog takes the union. No duplicates — relations are sets.