Unification joins assertions and renamed rules under one frame protocol.
Implement bidirectional variable unification, rule-variable renaming, assertion and rule search, negation-as-failure, and an explicit rule-depth budget.
Guiding question
What additional machinery lets a query match not only stored facts but also conclusions derived from reusable rules?
Unify variables appearing on either side of a comparison
Follow an existing variable binding before extending a frame
Rename every rule variable for each application
Apply a rule by unifying its conclusion and evaluating its body
Combine and, or, and finite negation-as-failure over frame lists
Bound recursive rule application with an explicit remaining depth
unify-match generalizes simple assertion matching. Either input may be a variable, and an existing binding may lead to another variable or structure before the comparison finishes. Before every rule application, rename-rule replaces each logical variable with a fresh key carrying the current rule-application id. This prevents a rule’s private intermediate names from colliding with query variables or another application of the same rule.
simple-query combines direct assertion matches with rule results. A rule result unifies the query pattern with the renamed conclusion, then sends the resulting frame through qeval on the rule body. and pipelines frames, or appends alternatives, and not keeps a frame only when its subquery has no result under that frame. The explicit depth is the exact finite resource boundary for rule expansion.
The engine returns (((grandchild carol) (grandchild dave)) (dave) 2).
Trace focus
Follow the query pattern into direct assertion matching and then into each renamed rule conclusion. Inspect the fresh variable keys before the grandparent body enters conjoin. For the negated parent query, show why carol is rejected and dave is retained. Confirm that the two or branches start from the same empty input frame.
Try it yourself
Change the program and compare the result.
Add an ancestor rule with a direct parent clause and a recursive clause. Run it with depth 4 and depth 1, report the answers separately, and explain how the work budget determines the result frontier.
Show hint
Use two rules with the same ancestor conclusion. The recursive body should introduce one fresh intermediate variable and call ancestor with the remaining depth budget.