Overview
A Datalog program in Zodd consists of facts, rules, and optional
queries.
Lines starting with % are treated as comments and are ignored.
The words not, count, sum, min, and max
are reserved keywords.
Basic Elements
- Constants: integers (such as
68) or double-quoted strings (such as
"alice"). Bare lowercase identifiers (such as alice) are not valid
constants.
- Variables: identifiers starting with an uppercase letter or an underscore (such as
X, Y, or the wildcard _).
- Facts: assertions of the form
predicate(constants). representing base
data.
edge(1, 2).
likes("alice", "tea").
- Rules: statements of the form
head :- body., where the body is a
comma-separated list of subgoals (predicates applied to variables or constants) and optional
comparison filters.
path(X, Y) :- edge(X, Y).
path(X, Z) :- path(X, Y), edge(Y, Z).
- Queries: requests of the form
?- predicate(arguments).. When a query
is present, the engine returns only matching tuples; otherwise, all derived relations are returned.
?- path(1, X).
Negation
Negated subgoals use the not keyword. To ensure rule safety, every variable in a negated
subgoal must also appear in at least one positive subgoal within the same rule body.
allowed(R, P) :- has_perm(R, P), not denied(R, P).
Comparison Filters
Zodd supports the comparison operators <, <=, >, >=,
=, and !=. Every variable in a comparison must be bound by a positive subgoal
in the rule body, and wildcards are not allowed. Ordered comparisons compare integers; a string operand
will fail the comparison.
Either side of a comparison may be an arithmetic expression over unsigned integers using +,
-, *, /, and parentheses. Arithmetic that does not produce a value
(a string operand, overflow, underflow, or division by zero) fails the comparison for that tuple.
hop(X, Y) :- edge(X, Y, W), W < 60.
reach(X, Z) :- reach(X, Y), hop(Y, Z), X != Z.
cheap(X, Y) :- edge(X, Y, W), (W + 10) * 2 < 140.
Assignments
Var is expr binds a fresh variable to the expression's value for each tuple. Every variable
on the right-hand side must already be bound, and the target must not be bound anywhere else in the
rule. An assignment whose expression produces no value derives nothing for that tuple. A recursive rule
that uses an assignment requires an iteration limit, because it can otherwise derive new values
forever.
dist(1, 0).
dist(Y, D2) :- dist(X, D), edge(X, Y), D2 is D + 1.
Aggregates
Zodd supports aggregation functions in the heads of rules. The supported functions are count,
sum, min, and max. The argument to an aggregation function must
be a single variable.
out_deg(N, count(M)) :- hop(N, M).
fanout(P, count(D)) :- needs(P, D).