;; lib/prolog/tests/set_predicates.sx — foldl/4, list_to_set/2, intersection/3, subtract/3, union/3 (define pl-sp-test-count 0) (define pl-sp-test-pass 0) (define pl-sp-test-fail 0) (define pl-sp-test-failures (list)) (define pl-sp-test! (fn (name got expected) (begin (set! pl-sp-test-count (+ pl-sp-test-count 1)) (if (= got expected) (set! pl-sp-test-pass (+ pl-sp-test-pass 1)) (begin (set! pl-sp-test-fail (+ pl-sp-test-fail 1)) (append! pl-sp-test-failures (str name "\n expected: " expected "\n got: " got))))))) (define pl-sp-goal (fn (src env) (pl-instantiate (nth (first (pl-parse (str "g :- " src "."))) 2) env))) ;; DB with add/3 for foldl tests (define pl-sp-db (pl-mk-db)) (pl-db-load! pl-sp-db (pl-parse "add(X, Acc, NAcc) :- NAcc is Acc + X.")) ;; ── foldl/4 ──────────────────────────────────────────────────────── (define pl-sp-env-fl1 {:S (pl-mk-rt-var "S")}) (pl-solve-once! pl-sp-db (pl-sp-goal "foldl(add, [1,2,3,4], 0, S)" pl-sp-env-fl1) (pl-mk-trail)) (pl-sp-test! "foldl(add,[1,2,3,4],0,S) -> S=10" (pl-num-val (pl-walk-deep (dict-get pl-sp-env-fl1 "S"))) 10) (define pl-sp-env-fl2 {:S (pl-mk-rt-var "S")}) (pl-solve-once! pl-sp-db (pl-sp-goal "foldl(add, [], 5, S)" pl-sp-env-fl2) (pl-mk-trail)) (pl-sp-test! "foldl(add,[],5,S) -> S=5" (pl-num-val (pl-walk-deep (dict-get pl-sp-env-fl2 "S"))) 5) (define pl-sp-env-fl3 {:S (pl-mk-rt-var "S")}) (pl-solve-once! pl-sp-db (pl-sp-goal "foldl(add, [1,2,3], 0, S)" pl-sp-env-fl3) (pl-mk-trail)) (pl-sp-test! "foldl(add,[1,2,3],0,S) -> S=6" (pl-num-val (pl-walk-deep (dict-get pl-sp-env-fl3 "S"))) 6) ;; ── list_to_set/2 ────────────────────────────────────────────────── (define pl-sp-env-lts1 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "list_to_set([1,2,3,2,1], R)" pl-sp-env-lts1) (pl-mk-trail)) (pl-sp-test! "list_to_set([1,2,3,2,1],R) -> [1,2,3]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-lts1 "R"))) ".(1, .(2, .(3, [])))") (define pl-sp-env-lts2 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "list_to_set([], R)" pl-sp-env-lts2) (pl-mk-trail)) (pl-sp-test! "list_to_set([],R) -> []" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-lts2 "R"))) "[]") (define pl-sp-env-lts3 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "list_to_set([a,b,a,c], R)" pl-sp-env-lts3) (pl-mk-trail)) (pl-sp-test! "list_to_set([a,b,a,c],R) -> [a,b,c]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-lts3 "R"))) ".(a, .(b, .(c, [])))") ;; ── intersection/3 ───────────────────────────────────────────────── (define pl-sp-env-int1 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "intersection([1,2,3,4], [2,4,6], R)" pl-sp-env-int1) (pl-mk-trail)) (pl-sp-test! "intersection([1,2,3,4],[2,4,6],R) -> [2,4]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-int1 "R"))) ".(2, .(4, []))") (define pl-sp-env-int2 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "intersection([1,2,3], [4,5,6], R)" pl-sp-env-int2) (pl-mk-trail)) (pl-sp-test! "intersection([1,2,3],[4,5,6],R) -> []" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-int2 "R"))) "[]") (define pl-sp-env-int3 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "intersection([], [1,2,3], R)" pl-sp-env-int3) (pl-mk-trail)) (pl-sp-test! "intersection([],[1,2,3],R) -> []" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-int3 "R"))) "[]") ;; ── subtract/3 ───────────────────────────────────────────────────── (define pl-sp-env-sub1 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "subtract([1,2,3,4], [2,4], R)" pl-sp-env-sub1) (pl-mk-trail)) (pl-sp-test! "subtract([1,2,3,4],[2,4],R) -> [1,3]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-sub1 "R"))) ".(1, .(3, []))") (define pl-sp-env-sub2 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "subtract([1,2,3], [], R)" pl-sp-env-sub2) (pl-mk-trail)) (pl-sp-test! "subtract([1,2,3],[],R) -> [1,2,3]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-sub2 "R"))) ".(1, .(2, .(3, [])))") (define pl-sp-env-sub3 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "subtract([], [1,2], R)" pl-sp-env-sub3) (pl-mk-trail)) (pl-sp-test! "subtract([],[1,2],R) -> []" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-sub3 "R"))) "[]") ;; ── union/3 ──────────────────────────────────────────────────────── (define pl-sp-env-uni1 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "union([1,2,3], [2,3,4], R)" pl-sp-env-uni1) (pl-mk-trail)) (pl-sp-test! "union([1,2,3],[2,3,4],R) -> [1,2,3,4]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-uni1 "R"))) ".(1, .(2, .(3, .(4, []))))") (define pl-sp-env-uni2 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "union([], [1,2], R)" pl-sp-env-uni2) (pl-mk-trail)) (pl-sp-test! "union([],[1,2],R) -> [1,2]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-uni2 "R"))) ".(1, .(2, []))") (define pl-sp-env-uni3 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-sp-db (pl-sp-goal "union([1,2], [], R)" pl-sp-env-uni3) (pl-mk-trail)) (pl-sp-test! "union([1,2],[],R) -> [1,2]" (pl-format-term (pl-walk-deep (dict-get pl-sp-env-uni3 "R"))) ".(1, .(2, []))") ;; ── Runner ───────────────────────────────────────────────────────── (define pl-set-predicates-tests-run! (fn () {:failed pl-sp-test-fail :passed pl-sp-test-pass :total pl-sp-test-count :failures pl-sp-test-failures}))