From f8b9bde1a559d62852f48105c7715ba1c7aeeae9 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 12:31:53 +0000 Subject: [PATCH] =?UTF-8?q?mk:=20zip-with-o=20=E2=80=94=20element-wise=20c?= =?UTF-8?q?ombine=20of=20two=20lists?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like Haskell's zipWith but relational. (zip-with-o rel l1 l2 result) applies a 3-arg combiner relation pointwise: rel l1[i] l2[i] result[i]. (zip-with-o pluso-i (list 1 2 3) (list 10 20 30) q) -> ((11 22 33)) (zip-with-o (fn (a b r) (== r (list a b))) (list :x :y) (list 1 2) q) -> (((:x 1) (:y 2))) Different-length lists fail. 5 new tests, 551/551 cumulative. --- lib/minikanren/relations.sx | 8 +++++ lib/minikanren/tests/zip-with-o.sx | 52 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 lib/minikanren/tests/zip-with-o.sx diff --git a/lib/minikanren/relations.sx b/lib/minikanren/relations.sx index 758d1df1..35d87cb5 100644 --- a/lib/minikanren/relations.sx +++ b/lib/minikanren/relations.sx @@ -277,6 +277,14 @@ ((nullo l1) (nullo l2) (nullo pairs)) ((fresh (a1 d1 a2 d2 d-pairs) (conso a1 d1 l1) (conso a2 d2 l2) (conso (list a1 a2) d-pairs pairs) (pairlisto d1 d2 d-pairs)))))) +(define + zip-with-o + (fn + (rel l1 l2 result) + (conde + ((nullo l1) (nullo l2) (nullo result)) + ((fresh (a1 d1 a2 d2 a-result d-result) (conso a1 d1 l1) (conso a2 d2 l2) (rel a1 a2 a-result) (conso a-result d-result result) (zip-with-o rel d1 d2 d-result)))))) + (define swap-firsto (fn diff --git a/lib/minikanren/tests/zip-with-o.sx b/lib/minikanren/tests/zip-with-o.sx new file mode 100644 index 00000000..c3cea9ab --- /dev/null +++ b/lib/minikanren/tests/zip-with-o.sx @@ -0,0 +1,52 @@ +;; lib/minikanren/tests/zip-with-o.sx — element-wise combine of two lists. + +(mk-test + "zip-with-o-empty" + (run* q (zip-with-o pluso-i (list) (list) q)) + (list (list))) + +(mk-test + "zip-with-o-pluso-i" + (run* + q + (zip-with-o + pluso-i + (list 1 2 3) + (list 10 20 30) + q)) + (list (list 11 22 33))) + +(mk-test + "zip-with-o-times-i" + (run* + q + (zip-with-o + *o-i + (list 2 3 4) + (list 5 6 7) + q)) + (list (list 10 18 28))) + +(mk-test + "zip-with-o-different-length-fails" + (run* + q + (zip-with-o + pluso-i + (list 1 2) + (list 1 2 3) + q)) + (list)) + +(mk-test + "zip-with-o-non-arith-rel" + (run* + q + (zip-with-o + (fn (a b r) (== r (list a b))) + (list :x :y) + (list 1 2) + q)) + (list (list (list :x 1) (list :y 2)))) + +(mk-tests-run!)