diff --git a/lib/minikanren/intarith.sx b/lib/minikanren/intarith.sx index f5351ece..015bea2d 100644 --- a/lib/minikanren/intarith.sx +++ b/lib/minikanren/intarith.sx @@ -93,3 +93,19 @@ (conde ((fresh (a) (== l (list a)) (== m a))) ((fresh (a d rest-max) (conso a d l) (maxo d rest-max) (conde ((lteo-i rest-max a) (== m a)) ((lto-i a rest-max) (== m rest-max)))))))) + +(define + sumo + (fn + (l total) + (conde + ((nullo l) (== total 0)) + ((fresh (a d rest-sum) (conso a d l) (sumo d rest-sum) (pluso-i a rest-sum total)))))) + +(define + producto + (fn + (l total) + (conde + ((nullo l) (== total 1)) + ((fresh (a d rest-prod) (conso a d l) (producto d rest-prod) (*o-i a rest-prod total)))))) diff --git a/lib/minikanren/tests/sum-product.sx b/lib/minikanren/tests/sum-product.sx new file mode 100644 index 00000000..6eddd96c --- /dev/null +++ b/lib/minikanren/tests/sum-product.sx @@ -0,0 +1,44 @@ +;; lib/minikanren/tests/sum-product.sx — fold list to integer. + +(mk-test "sumo-empty" (run* q (sumo (list) q)) (list 0)) +(mk-test + "sumo-1-to-5" + (run* + q + (sumo (list 1 2 3 4 5) q)) + (list 15)) +(mk-test + "sumo-zeros" + (run* q (sumo (list 0 0 0) q)) + (list 0)) +(mk-test + "sumo-negs" + (run* q (sumo (list 5 -3 8) q)) + (list 10)) + +(mk-test "producto-empty" (run* q (producto (list) q)) (list 1)) +(mk-test + "producto-1-to-4" + (run* q (producto (list 1 2 3 4) q)) + (list 24)) +(mk-test + "producto-with-0" + (run* q (producto (list 5 0 7) q)) + (list 0)) +(mk-test + "producto-of-1s" + (run* q (producto (list 1 1 1) q)) + (list 1)) + +(mk-test + "sum-product-pythagorean-square" + (run* + q + (fresh + (s sq2) + (sumo (list 3 4 5) s) + (producto (list 3 3) sq2) + (== q (list s sq2)))) + (list (list 12 9))) + +(mk-tests-run!) diff --git a/plans/minikanren-on-sx.md b/plans/minikanren-on-sx.md index 6f0c9ca4..5ba00636 100644 --- a/plans/minikanren-on-sx.md +++ b/plans/minikanren-on-sx.md @@ -173,6 +173,7 @@ _(none yet)_ _Newest first._ +- **2026-05-08** — **sumo + producto (intarith)**: fold a list of ground integers to its sum or product. Empty list -> identity (0 / 1). Recurse via pluso-i / *o-i. 9 new tests, 481/481 cumulative. - **2026-05-08** — **mino + maxo (intarith)**: find the minimum/maximum of a non-empty list of ground integers. Two conde clauses each: singleton (return the element) / multi (compare head against recursive min/max of tail). 9 new tests, 472/472 cumulative. - **2026-05-08** — **sortedo (intarith)**: list is non-decreasing under integer ordering. Three conde clauses: empty / singleton / pair-and-recurse. Uses lteo-i for the adjacent-pair check (ground integers). 7 new tests, 463/463 cumulative. - **2026-05-08** — **subseto**: every element of l1 is a member of l2. Recurses on l1, checking each element via membero. Allows duplicates in l1 (each independently in l2). 7 new tests, 456/456 cumulative.