From f33a8d69f56207c4574c5834e5baecb994562231 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 09:41:02 +0000 Subject: [PATCH] datalog: dl-eval source + query convenience (181/181) Single-call entry: dl-eval source-string query-string parses both, builds a db via dl-program, saturates implicitly, runs the query (extracted from the parsed `?- ...` clause), and returns the substitution list. Most user-friendly path: (dl-eval "parent(a, b). ..." "?- ancestor(a, X).") 2 new api tests cover ancestor and multi-goal usage. --- lib/datalog/api.sx | 20 ++++++++++++++++++++ lib/datalog/scoreboard.json | 8 ++++---- lib/datalog/scoreboard.md | 4 ++-- lib/datalog/tests/api.sx | 15 +++++++++++++++ plans/datalog-on-sx.md | 5 +++++ 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lib/datalog/api.sx b/lib/datalog/api.sx index a76d3624..872b2017 100644 --- a/lib/datalog/api.sx +++ b/lib/datalog/api.sx @@ -149,6 +149,26 @@ (dl-saturate! db) db)))) +;; ── Convenience: single-call source + query ─────────────────── +;; (dl-eval source query-source) parses both, builds a db, saturates, +;; runs the query, returns the substitution list. The query source +;; should be `?- goal[, goal ...].` — the parser produces a clause +;; with :query containing a list of literals which is fed straight +;; to dl-query. +(define + dl-eval + (fn + (source query-source) + (let + ((db (dl-program source)) + (queries (dl-parse query-source))) + (cond + ((= (len queries) 0) (error "dl-eval: query string is empty")) + ((not (has-key? (first queries) :query)) + (error "dl-eval: second arg must be a `?- ...` query clause")) + (else + (dl-query db (get (first queries) :query))))))) + (define dl-rule-head-rels (fn diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index 364e5284..39c21738 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 179, + "total_passed": 181, "total_failed": 0, - "total": 179, + "total": 181, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -12,8 +12,8 @@ {"name":"semi_naive","passed":8,"failed":0,"total":8}, {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":16,"failed":0,"total":16}, - {"name":"api","passed":11,"failed":0,"total":11}, + {"name":"api","passed":13,"failed":0,"total":13}, {"name":"demo","passed":18,"failed":0,"total":18} ], - "generated": "2026-05-08T09:38:47+00:00" + "generated": "2026-05-08T09:40:51+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index abb01eea..42982ee6 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**179 / 179 passing** (0 failure(s)). +**181 / 181 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -12,5 +12,5 @@ | semi_naive | 8 | 8 | ok | | negation | 10 | 10 | ok | | aggregates | 16 | 16 | ok | -| api | 11 | 11 | ok | +| api | 13 | 13 | ok | | demo | 18 | 18 | ok | diff --git a/lib/datalog/tests/api.sx b/lib/datalog/tests/api.sx index 577bafe9..6df9ce37 100644 --- a/lib/datalog/tests/api.sx +++ b/lib/datalog/tests/api.sx @@ -198,6 +198,21 @@ (list (quote (n X)) (list (string->symbol ">") (quote X) 2))) (list {:X 3} {:X 4} {:X 5})) + ;; dl-eval: single-call source + query. + (dl-api-test-set! "dl-eval ancestor" + (dl-eval + "parent(a, b). parent(b, c). + ancestor(X, Y) :- parent(X, Y). + ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z)." + "?- ancestor(a, X).") + (list {:X (quote b)} {:X (quote c)})) + + (dl-api-test-set! "dl-eval multi-goal" + (dl-eval + "p(1). p(2). p(3). q(2). q(3)." + "?- p(X), q(X).") + (list {:X 2} {:X 3})) + ;; dl-rule-from-list with no arrow → fact-style. (dl-api-test-set! "no arrow → fact-like rule" (let diff --git a/plans/datalog-on-sx.md b/plans/datalog-on-sx.md index 201faa8e..04e2948c 100644 --- a/plans/datalog-on-sx.md +++ b/plans/datalog-on-sx.md @@ -284,6 +284,11 @@ large graphs. _Newest first._ +- 2026-05-08 — Convenience: `dl-eval source query-source`. Parses + both strings, builds a db, saturates, runs the query, returns + the substitution list. Single-call user-friendly entry. 2 new + api tests cover ancestor and multi-goal queries. + - 2026-05-08 — Phase 6 stub: `dl-set-strategy! db strategy` and `dl-get-strategy db` user-facing hooks. Default `:semi-naive`; `:magic` is accepted but the actual transformation is deferred,