From 2a36e692f4e75acb985d73051729a8cda439123e Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 12:30:53 +0000 Subject: [PATCH] =?UTF-8?q?mk:=20take-while-o=20+=20drop-while-o=20?= =?UTF-8?q?=E2=80=94=20predicate-driven=20prefix/suffix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (take-while-o pred l result): take elements from l while pred holds, stopping at the first element that fails. (drop-while-o pred l result): drop matching elements, return the rest including the first non-match. Together: (take-while p l) ⊕ (drop-while p l) = l, verified by an end-to-end roundtrip test. 8 new tests, 546/546 cumulative. --- lib/minikanren/relations.sx | 16 ++++ lib/minikanren/tests/take-while-drop-while.sx | 80 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 lib/minikanren/tests/take-while-drop-while.sx diff --git a/lib/minikanren/relations.sx b/lib/minikanren/relations.sx index eff42820..758d1df1 100644 --- a/lib/minikanren/relations.sx +++ b/lib/minikanren/relations.sx @@ -89,6 +89,22 @@ ((fresh (a d r-rest) (conso a d l) (conde ((membero a d) (nub-o d result)) ((nafc (membero a d)) (conso a r-rest result) (nub-o d r-rest)))))))) +(define + take-while-o + (fn + (pred l result) + (conde + ((nullo l) (nullo result)) + ((fresh (a d r-rest) (conso a d l) (conde ((pred a) (conso a r-rest result) (take-while-o pred d r-rest)) ((nafc (pred a)) (== result (list))))))))) + +(define + drop-while-o + (fn + (pred l result) + (conde + ((nullo l) (nullo result)) + ((fresh (a d) (conso a d l) (conde ((pred a) (drop-while-o pred d result)) ((nafc (pred a)) (== result l)))))))) + (define membero (fn diff --git a/lib/minikanren/tests/take-while-drop-while.sx b/lib/minikanren/tests/take-while-drop-while.sx new file mode 100644 index 00000000..99cd69cd --- /dev/null +++ b/lib/minikanren/tests/take-while-drop-while.sx @@ -0,0 +1,80 @@ +;; lib/minikanren/tests/take-while-drop-while.sx — prefix/suffix by predicate. + +(mk-test + "take-while-o-empty" + (run* q (take-while-o (fn (x) (== x 1)) (list) q)) + (list (list))) + +(mk-test + "take-while-o-while-lt-5" + (run* + q + (take-while-o + (fn (x) (lto-i x 5)) + (list 1 3 7 2 9) + q)) + (list (list 1 3))) + +(mk-test + "take-while-o-all-match" + (run* + q + (take-while-o + (fn (x) (lto-i x 100)) + (list 1 2 3) + q)) + (list (list 1 2 3))) + +(mk-test + "take-while-o-none-match" + (run* + q + (take-while-o + (fn (x) (lto-i 100 x)) + (list 1 2 3) + q)) + (list (list))) + +(mk-test + "drop-while-o-empty" + (run* q (drop-while-o (fn (x) (== x 1)) (list) q)) + (list (list))) + +(mk-test + "drop-while-o-while-lt-5" + (run* + q + (drop-while-o + (fn (x) (lto-i x 5)) + (list 1 3 7 2 9) + q)) + (list (list 7 2 9))) + +(mk-test + "drop-while-o-all-match" + (run* + q + (drop-while-o + (fn (x) (lto-i x 100)) + (list 1 2 3) + q)) + (list (list))) + +(mk-test + "take-drop-roundtrip" + (run* + q + (fresh + (p s) + (take-while-o + (fn (x) (lto-i x 5)) + (list 1 3 7 2 9) + p) + (drop-while-o + (fn (x) (lto-i x 5)) + (list 1 3 7 2 9) + s) + (appendo p s q))) + (list (list 1 3 7 2 9))) + +(mk-tests-run!)