Declarative Rule Syntax
Real rule Head(args) :- Body. declarative syntax, run live below โ see the Grammar reference for the statement grammar and the goal-oriented demo for the equivalent hand-written rule_add call form this sugars over.
The parser has recognized rule ... :- ... syntax for a long time โ it just silently discarded it as a no-op. This makes it real: pure sugar over the same rule_add/solve backend as the goal-oriented demo above, so rule buildable(X) :- unchanged(X). and rule buildable(X) :- dep(X, Y), buildable(Y). now actually declare rules, not decoration. Verified byte-identical against the hand-written rule_add(...) function-call form it desugars to.
PatLang source
# Real `rule Head(args) :- Body1, Body2.` declarative syntax (Stage B),
# proving it's genuine sugar over the already-working rule_add/solve
# backend -- same multi-hop chaining, backtracking, and GOAP planning as
# self_hosting/examples/goal_oriented_build_demo.patlang, just spelled the
# way the paradigm is supposed to read. Confirmed byte-identical output
# against the hand-written rule_add(...) version this was ported from.
# `rule Head(args).` -- a fact (a rule with an empty body, the standard
# Prolog trick, matching how rule_add already treats an empty body list).
rule dep(a, b).
rule dep(b, c).
rule unchanged(c).
# `rule Head(args) :- Body1, Body2.` -- a real rule with a body.
# buildable(X) :- unchanged(X).
# buildable(X) :- dep(X, Y), buildable(Y).
rule buildable(X) :- unchanged(X).
rule buildable(X) :- dep(X, Y), buildable(Y).
let sols_a = solve("buildable", ["a"])
print("buildable(a) via a->b->c, c unchanged: " + list_len(sols_a) + " solution(s)")
rule dep(d, e).
let sols_d = solve("buildable", ["d"])
print("buildable(d) via d->e, e never unchanged: " + list_len(sols_d) + " solution(s) (should be 0)")
print("DONE")
(not run yet)
Native run on the build machine:
buildable(a) via a->b->c, c unchanged: 1 solution(s) buildable(d) via d->e, e never unchanged: 0 solution(s) (should be 0) DONE