datalog: built-ins + body arithmetic + order-aware safety (Phase 4, 106/106)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s

New lib/datalog/builtins.sx: (< <= > >= = !=) and (is X expr) with
+ - * /. dl-eval-arith recursively evaluates nested compounds.
Safety analysis now walks body left-to-right tracking the bound
set: comparisons require all args bound, is RHS vars must be bound
(LHS becomes bound), = special-cases the var/non-var combos.
db.sx keeps the simple safety check as a forward-reference
fallback; builtins.sx redefines dl-rule-check-safety to the
comprehensive version. eval.sx dispatches built-ins through
dl-eval-builtin instead of erroring. 19 new tests.
This commit is contained in:
2026-05-07 23:51:21 +00:00
parent 6457eb668c
commit 7ce723f732
8 changed files with 617 additions and 110 deletions

View File

@@ -4,11 +4,11 @@
;; The Herbrand base is finite (no function symbols) so termination is
;; guaranteed by the language.
;;
;; Phase 3 handles only positive EDB literals. Negation (Phase 7) and
;; arithmetic built-ins (Phase 4) raise a clear error if encountered.
;; Body literal kinds handled here:
;; positive (rel arg ... arg) → match against EDB+IDB tuples (dl-match-positive)
;; built-in (< X Y), (is X e) → constraint via dl-eval-builtin (Phase 4)
;; negation {:neg lit} → Phase 7
;; Match a positive literal against every tuple in the relation; return
;; a list of extended substitutions, one per successful unification.
(define
dl-match-positive
(fn
@@ -38,13 +38,13 @@
((and (dict? lit) (has-key? lit :neg))
(error "datalog: negation not yet supported (Phase 7)"))
((dl-builtin? lit)
(error "datalog: built-in predicate not yet supported (Phase 4)"))
(let
((s (dl-eval-builtin lit subst)))
(if (nil? s) (list) (list s))))
((and (list? lit) (> (len lit) 0))
(dl-match-positive lit db subst))
(else (error (str "datalog: unknown body-literal shape: " lit))))))
;; Recursively find all substitutions satisfying a list of body literals
;; under `subst`. Returns a list of substitutions.
(define
dl-find-bindings
(fn
@@ -66,7 +66,6 @@
options)
results))))))
;; Apply a rule once. Returns true if any new tuple was derived.
(define
dl-apply-rule!
(fn
@@ -83,7 +82,6 @@
(dl-find-bindings body db (dl-empty-subst)))
new?))))
;; Iterate rules to fixpoint.
(define
dl-saturate!
(fn
@@ -106,9 +104,6 @@
(dl-sat-loop)
db))))
;; Run a goal against the saturated db. Returns a list of substitutions
;; (each restricted to the variables that appeared in `goal`). Duplicate
;; projections are deduplicated so users get the set of answers.
(define
dl-query
(fn
@@ -131,7 +126,6 @@
substs)
results)))))
;; Project a subst down to a given set of variable names.
(define
dl-project-subst
(fn