diff --git a/lib/minikanren/relations.sx b/lib/minikanren/relations.sx index b9f382c5..6423a759 100644 --- a/lib/minikanren/relations.sx +++ b/lib/minikanren/relations.sx @@ -188,3 +188,19 @@ (conde ((== n :z) (== suffix l)) ((fresh (n-1 a d) (== n (list :s n-1)) (conso a d l) (dropo n-1 d suffix)))))) + +(define + repeato + (fn + (x n result) + (conde + ((== n :z) (== result (list))) + ((fresh (n-1 r-rest) (== n (list :s n-1)) (conso x r-rest result) (repeato x n-1 r-rest)))))) + +(define + concato + (fn + (lists result) + (conde + ((nullo lists) (nullo result)) + ((fresh (h t r-rest) (conso h t lists) (appendo h r-rest result) (concato t r-rest)))))) diff --git a/lib/minikanren/tests/repeato-concato.sx b/lib/minikanren/tests/repeato-concato.sx new file mode 100644 index 00000000..ff730413 --- /dev/null +++ b/lib/minikanren/tests/repeato-concato.sx @@ -0,0 +1,69 @@ +;; lib/minikanren/tests/repeato-concato.sx — repeat element n times + +;; concatenate a list of lists. + +(define + mk-nat + (fn (n) (if (= n 0) :z (list :s (mk-nat (- n 1)))))) + +;; --- repeato --- + +(mk-test + "repeato-zero" + (run* q (repeato :a (mk-nat 0) q)) + (list (list))) +(mk-test + "repeato-one" + (run* q (repeato :a (mk-nat 1) q)) + (list (list :a))) +(mk-test + "repeato-three" + (run* q (repeato :a (mk-nat 3) q)) + (list (list :a :a :a))) + +(mk-test + "repeato-numeric" + (run* q (repeato 7 (mk-nat 4) q)) + (list (list 7 7 7 7))) + +(mk-test + "repeato-recover-count" + (run* q (repeato :x q (list :x :x :x :x))) + (list (mk-nat 4))) + +;; --- concato --- + +(mk-test "concato-empty" (run* q (concato (list) q)) (list (list))) + +(mk-test + "concato-single" + (run* q (concato (list (list 1 2 3)) q)) + (list (list 1 2 3))) + +(mk-test + "concato-multi" + (run* + q + (concato + (list + (list 1 2) + (list 3) + (list 4 5 6)) + q)) + (list + (list 1 2 3 4 5 6))) + +(mk-test + "concato-all-empty" + (run* q (concato (list (list) (list) (list)) q)) + (list (list))) + +(mk-test + "concato-mixed-empty" + (run* + q + (concato + (list (list 1) (list) (list 2 3)) + q)) + (list (list 1 2 3))) + +(mk-tests-run!) diff --git a/plans/minikanren-on-sx.md b/plans/minikanren-on-sx.md index a2640338..9f5749a6 100644 --- a/plans/minikanren-on-sx.md +++ b/plans/minikanren-on-sx.md @@ -173,6 +173,10 @@ _(none yet)_ _Newest first._ +- **2026-05-08** — **repeato + concato**: repeato builds a list of n copies + (Peano n); concato is fold-appendo over a list of lists. Both run forward + and backward — repeato can recover the count from a uniform list. 10 new + tests, 378/378 cumulative. - **2026-05-08** — **tako + dropo (Peano-indexed prefix/suffix)**: takes / drops the first n elements via a Peano-encoded count. Round-trip `(tako n l) ⊕ (dropo n l) = l` holds. 9 new tests, 368/368 cumulative.