Negation
Asking what isn't there with not, and the two rules that keep it well defined: anchoring and stratification.
not asks for something to be absent. A package is untested when no test fact names it, so:
For each package, not test(_, ?p) holds when there’s no test of any name for that package. A _ inside a not stands for any value, so you’re asking that no test exists at all rather than about one particular test. The same shape finds the packages nothing imports, which are where a dependency graph starts:
Negation in a rule ¶
A rule can use not too, and other rules and goals can build on it. This defines untested once, then asks which of app’s dependencies are untested:
depends_on(?a, ?b) :- imports(?a, ?b);
depends_on(?a, ?c) :- depends_on(?a, ?b), imports(?b, ?c);
untested(?p) :- package(?p), not test(_, ?p);
depends_on("app", ?p), untested(?p) => ?p| ?p |
|---|
| cache |
| config |
| log |
deps datasetA not has to be anchored ¶
jaala checks a not row by row, so it has to share a variable with the positive part of the goal, the part that produces rows. Here ?t and ?q appear only inside the not, so it doesn’t depend on the row at all:
package(?p), not test(?t, ?q) => ?pquery: negated relation "test" shares no variable with the rest of the query (?t appears only inside the `not`, so the negation has nothing to range over and matches either every row or none)
deps datasetAs written, that not would hold for every package or for none, depending on whether any test exists anywhere, which is almost never what you meant. So jaala refuses it and says which variable has nothing to range over. The fix is usually a variable that was meant to be shared, and not test(?t, ?p) asks about this package’s tests.
Stratification ¶
A rule can’t depend on its own negation. This one says a package is odd when it isn’t odd, which has no consistent answer:
odd(?p) :- package(?p), not odd(?p);
odd(?p) => ?pquery: rules are not stratifiable (recursion through negation: odd)
deps datasetjaala sorts rules into strata, so that it finishes deriving everything a not reads before it runs the rule reading it. A cycle through a not (a rule reaching its own negation, here directly, more often through other rules) can’t be sorted, so jaala refuses the query up front rather than answer from a half-built relation. Recursion without negation, like depends_on, is fine, and it’s a bit of a relief that the line falls there.