datalog: findall aggregate (159/159)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s

(findall L V Goal) — bind L to the distinct V values for which Goal
holds, or the empty list when none. One-line addition to
dl-do-aggregate that returns the unreduced list. Tests cover EDB,
derived relation, and empty cases.

Useful for "give me all the X such that ..." queries without
scalar reduction.
This commit is contained in:
2026-05-08 09:02:43 +00:00
parent 5a1dc4392f
commit 55286cc5bc
5 changed files with 46 additions and 10 deletions

View File

@@ -19,7 +19,7 @@
;;
;; Empty input: count → 0, sum → 0, min/max → no binding (rule fails).
(define dl-aggregate-rels (list "count" "sum" "min" "max"))
(define dl-aggregate-rels (list "count" "sum" "min" "max" "findall"))
(define
dl-aggregate?
@@ -43,6 +43,7 @@
(cond
((= op "count") (len vals))
((= op "sum") (dl-sum-vals vals 0))
((= op "findall") vals)
((= op "min")
(cond
((= (len vals) 0) :empty)

View File

@@ -1,8 +1,8 @@
{
"lang": "datalog",
"total_passed": 156,
"total_passed": 159,
"total_failed": 0,
"total": 156,
"total": 159,
"suites": [
{"name":"tokenize","passed":26,"failed":0,"total":26},
{"name":"parse","passed":18,"failed":0,"total":18},
@@ -11,9 +11,9 @@
{"name":"builtins","passed":19,"failed":0,"total":19},
{"name":"semi_naive","passed":8,"failed":0,"total":8},
{"name":"negation","passed":10,"failed":0,"total":10},
{"name":"aggregates","passed":10,"failed":0,"total":10},
{"name":"aggregates","passed":13,"failed":0,"total":13},
{"name":"api","passed":9,"failed":0,"total":9},
{"name":"demo","passed":10,"failed":0,"total":10}
],
"generated": "2026-05-08T08:57:57+00:00"
"generated": "2026-05-08T09:02:31+00:00"
}

View File

@@ -1,6 +1,6 @@
# datalog scoreboard
**156 / 156 passing** (0 failure(s)).
**159 / 159 passing** (0 failure(s)).
| Suite | Passed | Total | Status |
|-------|--------|-------|--------|
@@ -11,6 +11,6 @@
| builtins | 19 | 19 | ok |
| semi_naive | 8 | 8 | ok |
| negation | 10 | 10 | ok |
| aggregates | 10 | 10 | ok |
| aggregates | 13 | 13 | ok |
| api | 9 | 9 | ok |
| demo | 10 | 10 | ok |

View File

@@ -199,6 +199,33 @@
(list (quote popular) (quote P)))
(list {:P (quote p1)}))
;; findall: collect distinct values into a list.
(dl-at-test-set! "findall over EDB"
(dl-query
(dl-program
"p(a). p(b). p(c).
all_p(L) :- findall(L, X, p(X)).")
(list (quote all_p) (quote L)))
(list {:L (list (quote a) (quote b) (quote c))}))
(dl-at-test-set! "findall over derived"
(dl-query
(dl-program
"parent(a, b). parent(b, c). parent(c, d).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).
desc(L) :- findall(L, X, ancestor(a, X)).")
(list (quote desc) (quote L)))
(list {:L (list (quote b) (quote c) (quote d))}))
(dl-at-test-set! "findall empty"
(dl-query
(dl-program
"p(1).
all_q(L) :- findall(L, X, q(X)).")
(list (quote all_q) (quote L)))
(list {:L (list)}))
;; Aggregate vs single distinct.
(dl-at-test-set! "distinct counted once"
(dl-query

View File

@@ -186,9 +186,10 @@ large graphs.
### Phase 8 — aggregation (Datalog+)
- [x] `(count R V Goal)`, `(sum R V Goal)`, `(min R V Goal)`,
`(max R V Goal)` — first arg is the result variable, second is the
aggregated variable, third is the goal literal. Live in
`lib/datalog/aggregates.sx`.
`(max R V Goal)`, `(findall L V Goal)` — first arg is the result
variable, second is the aggregated variable, third is the goal
literal. `findall` returns the distinct-value list itself; the
others reduce. Live in `lib/datalog/aggregates.sx`.
- [x] `dl-eval-aggregate`: runs `dl-find-bindings` on the goal under the
current subst (which provides outer-context bindings), collects
distinct values of the aggregated var, applies the aggregate.
@@ -269,6 +270,13 @@ large graphs.
_Newest first._
- 2026-05-08 — Phase 8 extension: `findall L V Goal` aggregate. Bind
L to the list of distinct V values for which Goal holds (or the
empty list when no matches). Implemented as a one-line case in
`dl-do-aggregate`. 3 new tests: EDB, derived relation, empty.
Useful for "give me all the X such that …" queries without
scalar reduction.
- 2026-05-08 — Phase 5d semantic fix: anonymous `_` variables are
renamed per occurrence at `dl-add-rule!` and `dl-query` time so
`(p X _) (p _ Y)` no longer unifies the two `_`s. New helpers