diff --git a/lib/minikanren/relations.sx b/lib/minikanren/relations.sx index 73bfd532..8a2cdcda 100644 --- a/lib/minikanren/relations.sx +++ b/lib/minikanren/relations.sx @@ -148,6 +148,15 @@ ((fresh (a d) (conso a d l) (== a x) (== out d))) ((fresh (a d res) (conso a d l) (nafc (== a x)) (conso a res out) (rembero x d res)))))) +(define + removeo-allo + (fn + (x l result) + (conde + ((nullo l) (nullo result)) + ((fresh (a d) (conso a d l) (== a x) (removeo-allo x d result))) + ((fresh (a d r-rest) (conso a d l) (nafc (== a x)) (conso a r-rest result) (removeo-allo x d r-rest)))))) + (define assoco (fn diff --git a/lib/minikanren/tests/removeo-allo.sx b/lib/minikanren/tests/removeo-allo.sx new file mode 100644 index 00000000..b7dd8a31 --- /dev/null +++ b/lib/minikanren/tests/removeo-allo.sx @@ -0,0 +1,39 @@ +;; lib/minikanren/tests/removeo-allo.sx — remove every occurrence of x. + +(mk-test + "removeo-allo-multi" + (run* + q + (removeo-allo + 2 + (list 1 2 3 2 4 2) + q)) + (list (list 1 3 4))) + +(mk-test + "removeo-allo-single" + (run* + q + (removeo-allo 2 (list 1 2 3) q)) + (list (list 1 3))) + +(mk-test + "removeo-allo-no-match" + (run* + q + (removeo-allo 99 (list 1 2 3) q)) + (list (list 1 2 3))) + +(mk-test + "removeo-allo-everything" + (run* + q + (removeo-allo 1 (list 1 1 1) q)) + (list (list))) + +(mk-test + "removeo-allo-empty" + (run* q (removeo-allo 1 (list) q)) + (list (list))) + +(mk-tests-run!) diff --git a/plans/minikanren-on-sx.md b/plans/minikanren-on-sx.md index 0bb00f17..d04acc87 100644 --- a/plans/minikanren-on-sx.md +++ b/plans/minikanren-on-sx.md @@ -173,6 +173,7 @@ _(none yet)_ _Newest first._ +- **2026-05-08** — **removeo-allo**: removes every occurrence of x (vs rembero, which removes only the first). Three conde clauses: empty -> empty; head matches -> skip and recurse; head differs (nafc) -> keep and recurse. 5 new tests, 446/446 cumulative. - **2026-05-08** — **btree-walko (matche showcase)**: walks a binary tree (:leaf v) | (:node l r) and emits each leaf value via conde. Demonstrates matche dispatch on tagged-list patterns, recursion through both branches via conde, and run* enumerating all 5 leaves of a small tree. 4 new tests, 441/441 cumulative. - **2026-05-08** — **swap-firsto**: swap the first two elements of a list. Built via four conso constraints. Self-inverse on length-2+ lists; runs forward and backward. 6 new tests, 437/437 cumulative. - **2026-05-08** — **pairlisto**: relational zip — pairs is the zipped list of (l1[i] l2[i]). Runs forward, recovers l1 given l2 and pairs, recovers l2 given l1 and pairs. 5 new tests, 431/431 cumulative.