Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 57s
Squash merge of 76 commits from loops/minikanren. Adds lib/minikanren/ — a complete miniKanren-on-SX implementation built on top of lib/guest/match.sx, validating the lib-guest unify-and-match kit as intended. Modules (20 .sx files, ~1700 LOC): unify, stream, goals, fresh, conde, condu, conda, run, relations, peano, intarith, project, nafc, matche, fd, queens, defrel, clpfd, tabling Phases 1–5 fully done (core miniKanren API, all classic relations, matche, conda, project, nafc). Phase 6 — native CLP(FD): domain primitives, fd-in / fd-eq / fd-neq / fd-lt / fd-lte / fd-plus / fd-times / fd-distinct / fd-label, with constraint reactivation iterating to fixed point. N-queens via FD: 4-queens 2 solutions, 5-queens 10 solutions (vs naive timeout past N=4). Phase 7 — naive ground-arg tabling: table-1 / table-2 / table-3. Fibonacci canary: tab-fib(25) = 75025 in seconds, naive fib(25) times out at 60s. Ackermann via table-3: A(3,3) = 61. 71 test files, 644+ tests passing across the suite. Producer/consumer SLG (cyclic patho, mutual recursion) deferred — research-grade work. The lib-guest validation experiment is conclusive: lib/minikanren/ unify.sx adds ~50 lines of local logic (custom cfg, deep walk*, fresh counter) over lib/guest/match.sx's ~100-line kit. The kit earns its keep ~3× by line count.
90 lines
2.2 KiB
Plaintext
90 lines
2.2 KiB
Plaintext
;; lib/minikanren/tests/conde.sx — Phase 2 piece C tests for `conde`.
|
|
;;
|
|
;; Note on ordering: conde clauses are wrapped in Zzz (inverse-eta delay),
|
|
;; so applying the conde goal to a substitution returns thunks. mk-mplus
|
|
;; suspends-and-swaps when its left operand is paused, giving fair
|
|
;; interleaving — this is exactly what makes recursive relations work,
|
|
;; but it does mean conde answers can interleave rather than appear in
|
|
;; strict left-to-right clause order.
|
|
|
|
;; --- single-clause conde ≡ conj of clause body ---
|
|
|
|
(mk-test
|
|
"conde-one-clause"
|
|
(let ((q (mk-var "q"))) (run* q (conde ((== q 7)))))
|
|
(list 7))
|
|
|
|
(mk-test
|
|
"conde-one-clause-multi-goals"
|
|
(let
|
|
((q (mk-var "q")))
|
|
(run* q (conde ((fresh (x) (== x 5) (== q (list x x)))))))
|
|
(list (list 5 5)))
|
|
|
|
;; --- multi-clause: produces one row per clause (interleaved) ---
|
|
|
|
(mk-test
|
|
"conde-three-clauses-as-set"
|
|
(let
|
|
((qs (run* q (conde ((== q 1)) ((== q 2)) ((== q 3))))))
|
|
(and
|
|
(= (len qs) 3)
|
|
(and
|
|
(some (fn (x) (= x 1)) qs)
|
|
(and
|
|
(some (fn (x) (= x 2)) qs)
|
|
(some (fn (x) (= x 3)) qs)))))
|
|
true)
|
|
|
|
(mk-test
|
|
"conde-mixed-success-failure-as-set"
|
|
(let
|
|
((qs (run* q (conde ((== q "a")) ((== 1 2)) ((== q "b"))))))
|
|
(and
|
|
(= (len qs) 2)
|
|
(and (some (fn (x) (= x "a")) qs) (some (fn (x) (= x "b")) qs))))
|
|
true)
|
|
|
|
;; --- conde with conjuncts inside clauses ---
|
|
|
|
(mk-test
|
|
"conde-clause-conj-as-set"
|
|
(let
|
|
((rows (run* q (fresh (x y) (conde ((== x 1) (== y 10)) ((== x 2) (== y 20))) (== q (list x y))))))
|
|
(and
|
|
(= (len rows) 2)
|
|
(and
|
|
(some (fn (r) (= r (list 1 10))) rows)
|
|
(some (fn (r) (= r (list 2 20))) rows))))
|
|
true)
|
|
|
|
;; --- nested conde ---
|
|
|
|
(mk-test
|
|
"conde-nested-yields-three"
|
|
(let
|
|
((qs (run* q (conde ((conde ((== q 1)) ((== q 2)))) ((== q 3))))))
|
|
(and
|
|
(= (len qs) 3)
|
|
(and
|
|
(some (fn (x) (= x 1)) qs)
|
|
(and
|
|
(some (fn (x) (= x 2)) qs)
|
|
(some (fn (x) (= x 3)) qs)))))
|
|
true)
|
|
|
|
;; --- conde all clauses fail → empty stream ---
|
|
|
|
(mk-test
|
|
"conde-all-fail"
|
|
(run*
|
|
q
|
|
(conde ((== 1 2)) ((== 3 4))))
|
|
(list))
|
|
|
|
;; --- empty conde: no clauses ⇒ fail ---
|
|
|
|
(mk-test "conde-no-clauses" (run* q (conde)) (list))
|
|
|
|
(mk-tests-run!)
|