From f5ab66e1a3dcbf4b518647c8f6eacef0adc59017 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 12:23:40 +0000 Subject: [PATCH] =?UTF-8?q?mk:=20foldl-o=20=E2=80=94=20relational=20left?= =?UTF-8?q?=20fold?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complement to foldr-o. The combiner relation has signature (acc head new-acc) — accumulator first. Examples: (foldl-o pluso-i (list 1 2 3 4 5) 0 q) -> (15) (foldl-o *o-i (list 1 2 3 4) 1 q) -> (24) (foldl-o (fn (acc x r) (conso x acc r)) ; flipped conso (list 1 2 3 4) (list) q) -> ((4 3 2 1)) ; reverse 5 new tests, 510/510 cumulative. --- lib/minikanren/relations.sx | 10 ++++++- lib/minikanren/tests/foldl-o.sx | 48 +++++++++++++++++++++++++++++++++ plans/minikanren-on-sx.md | 1 + 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 lib/minikanren/tests/foldl-o.sx diff --git a/lib/minikanren/relations.sx b/lib/minikanren/relations.sx index ac340736..c9b8b24e 100644 --- a/lib/minikanren/relations.sx +++ b/lib/minikanren/relations.sx @@ -64,6 +64,14 @@ ((nullo l) (== result acc)) ((fresh (a d r-rest) (conso a d l) (foldr-o rel d acc r-rest) (rel a r-rest result)))))) +(define + foldl-o + (fn + (rel l acc result) + (conde + ((nullo l) (== result acc)) + ((fresh (a d new-acc) (conso a d l) (rel acc a new-acc) (foldl-o rel d new-acc result)))))) + (define membero (fn @@ -80,6 +88,7 @@ ((nullo l)) ((fresh (a d) (conso a d l) (nafc (== a x)) (not-membero x d)))))) + (define subseto (fn @@ -88,7 +97,6 @@ ((nullo l1)) ((fresh (a d) (conso a d l1) (membero a l2) (subseto d l2)))))) - (define reverseo (fn diff --git a/lib/minikanren/tests/foldl-o.sx b/lib/minikanren/tests/foldl-o.sx new file mode 100644 index 00000000..2e196e43 --- /dev/null +++ b/lib/minikanren/tests/foldl-o.sx @@ -0,0 +1,48 @@ +;; lib/minikanren/tests/foldl-o.sx — relational left fold. + +(mk-test + "foldl-o-empty" + (run* q (foldl-o pluso-i (list) 42 q)) + (list 42)) + +(mk-test + "foldl-o-sum" + (run* + q + (foldl-o + pluso-i + (list 1 2 3 4 5) + 0 + q)) + (list 15)) + +(mk-test + "foldl-o-product" + (run* + q + (foldl-o + *o-i + (list 1 2 3 4) + 1 + q)) + (list 24)) + +(mk-test + "foldl-o-reverse-via-flip-conso" + (run* + q + (foldl-o + (fn (acc x r) (conso x acc r)) + (list 1 2 3 4) + (list) + q)) + (list (list 4 3 2 1))) + +(mk-test + "foldl-o-with-init" + (run* + q + (foldl-o pluso-i (list 1 2 3) 100 q)) + (list 106)) + +(mk-tests-run!) diff --git a/plans/minikanren-on-sx.md b/plans/minikanren-on-sx.md index d0903e32..30519136 100644 --- a/plans/minikanren-on-sx.md +++ b/plans/minikanren-on-sx.md @@ -173,6 +173,7 @@ _(none yet)_ _Newest first._ +- **2026-05-08** — **foldl-o (relational left fold)**: complement to foldr-o. Combiner has args (acc, head) -> new-acc. (foldl-o pluso-i (1 2 3 4 5) 0 q) -> 15; (foldl-o flipped-conso l () q) reverses l. 5 new tests, 510/510 cumulative. - **2026-05-08** — **foldr-o (relational right fold)**: takes a 3-arg combiner relation rel, a list, an initial accumulator, produces the result. (foldr-o appendo lists () q) is a flatten; (foldr-o conso l () q) rebuilds l. 4 new tests, 505/505 cumulative. - **2026-05-08** — **enumerate-i / enumerate-from-i — 500-test milestone**: index-each-element relations. (enumerate-i l result) -> result is l with each element paired with its 0-based index. (enumerate-from-i n l result) starts at n. 5 new tests, **501/501** cumulative. - **2026-05-08** — **partitiono**: relational partition. (partitiono pred l yes no) splits l so yes contains elements where pred succeeds and no contains the rest. Composes with intarith for numeric predicates. 5 new tests, 496/496 cumulative.