;; lib/prolog/tests/advanced.sx — predsort/3, term_variables/2, arith extensions (define pl-adv-test-count 0) (define pl-adv-test-pass 0) (define pl-adv-test-fail 0) (define pl-adv-test-failures (list)) (define pl-adv-test! (fn (name got expected) (begin (set! pl-adv-test-count (+ pl-adv-test-count 1)) (if (= got expected) (set! pl-adv-test-pass (+ pl-adv-test-pass 1)) (begin (set! pl-adv-test-fail (+ pl-adv-test-fail 1)) (append! pl-adv-test-failures (str name "\n expected: " expected "\n got: " got))))))) (define pl-adv-goal (fn (src env) (pl-instantiate (nth (first (pl-parse (str "g :- " src "."))) 2) env))) (define pl-adv-db (pl-mk-db)) ;; Load a numeric comparator for predsort tests (pl-db-load! pl-adv-db (pl-parse "cmp_num(Order, X, Y) :- (X < Y -> Order = '<' ; (X > Y -> Order = '>' ; Order = '=')).")) ;; ── Arithmetic extensions ────────────────────────────────────────── (define pl-adv-arith-env-1 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is floor(3.7)" pl-adv-arith-env-1) (pl-mk-trail)) (pl-adv-test! "floor(3.7) = 3" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-1 "X"))) 3) (define pl-adv-arith-env-2 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is ceiling(3.2)" pl-adv-arith-env-2) (pl-mk-trail)) (pl-adv-test! "ceiling(3.2) = 4" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-2 "X"))) 4) (define pl-adv-arith-env-3 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is truncate(3.9)" pl-adv-arith-env-3) (pl-mk-trail)) (pl-adv-test! "truncate(3.9) = 3" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-3 "X"))) 3) (define pl-adv-arith-env-4 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is truncate(0 - 3.9)" pl-adv-arith-env-4) (pl-mk-trail)) (pl-adv-test! "truncate(0-3.9) = -3" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-4 "X"))) -3) (define pl-adv-arith-env-5 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is round(3.5)" pl-adv-arith-env-5) (pl-mk-trail)) (pl-adv-test! "round(3.5) = 4" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-5 "X"))) 4) (define pl-adv-arith-env-6 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is sqrt(4.0)" pl-adv-arith-env-6) (pl-mk-trail)) (pl-adv-test! "sqrt(4.0) = 2" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-6 "X"))) 2) (define pl-adv-arith-env-7 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is sign(0 - 5)" pl-adv-arith-env-7) (pl-mk-trail)) (pl-adv-test! "sign(0-5) = -1" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-7 "X"))) -1) (define pl-adv-arith-env-8 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is sign(0)" pl-adv-arith-env-8) (pl-mk-trail)) (pl-adv-test! "sign(0) = 0" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-8 "X"))) 0) (define pl-adv-arith-env-9 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is sign(3)" pl-adv-arith-env-9) (pl-mk-trail)) (pl-adv-test! "sign(3) = 1" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-9 "X"))) 1) (define pl-adv-arith-env-10 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is pow(2, 3)" pl-adv-arith-env-10) (pl-mk-trail)) (pl-adv-test! "pow(2,3) = 8" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-10 "X"))) 8) (define pl-adv-arith-env-11 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is floor(0 - 3.7)" pl-adv-arith-env-11) (pl-mk-trail)) (pl-adv-test! "floor(0-3.7) = -4" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-11 "X"))) -4) (define pl-adv-arith-env-12 {:X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "X is ceiling(0 - 3.2)" pl-adv-arith-env-12) (pl-mk-trail)) (pl-adv-test! "ceiling(0-3.2) = -3" (pl-num-val (pl-walk-deep (dict-get pl-adv-arith-env-12 "X"))) -3) ;; ── term_variables/2 ────────────────────────────────────────────── (define pl-adv-tv-env-1 {:Vs (pl-mk-rt-var "Vs")}) (pl-solve-once! pl-adv-db (pl-adv-goal "term_variables(hello, Vs)" pl-adv-tv-env-1) (pl-mk-trail)) (pl-adv-test! "term_variables(hello,Vs) -> []" (pl-format-term (pl-walk-deep (dict-get pl-adv-tv-env-1 "Vs"))) "[]") (define pl-adv-tv-env-2 {:Vs (pl-mk-rt-var "Vs")}) (pl-solve-once! pl-adv-db (pl-adv-goal "term_variables(f(a, g(b)), Vs)" pl-adv-tv-env-2) (pl-mk-trail)) (pl-adv-test! "term_variables(f(a,g(b)),Vs) -> []" (pl-format-term (pl-walk-deep (dict-get pl-adv-tv-env-2 "Vs"))) "[]") (define pl-adv-tv-env-3 {:Y (pl-mk-rt-var "Y") :Vs (pl-mk-rt-var "Vs") :X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "term_variables(f(X, Y), Vs)" pl-adv-tv-env-3) (pl-mk-trail)) (pl-adv-test! "term_variables(f(X,Y),Vs) has 2 vars" (pl-list-length (pl-walk-deep (dict-get pl-adv-tv-env-3 "Vs"))) 2) (define pl-adv-tv-env-4 {:Vs (pl-mk-rt-var "Vs") :X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "term_variables(X, Vs)" pl-adv-tv-env-4) (pl-mk-trail)) (pl-adv-test! "term_variables(X,Vs) has 1 var" (pl-list-length (pl-walk-deep (dict-get pl-adv-tv-env-4 "Vs"))) 1) (define pl-adv-tv-env-5 {:Y (pl-mk-rt-var "Y") :Vs (pl-mk-rt-var "Vs") :X (pl-mk-rt-var "X")}) (pl-solve-once! pl-adv-db (pl-adv-goal "term_variables(foo(X, Y, X), Vs)" pl-adv-tv-env-5) (pl-mk-trail)) (pl-adv-test! "term_variables(foo(X,Y,X),Vs) deduplicates X -> 2 vars" (pl-list-length (pl-walk-deep (dict-get pl-adv-tv-env-5 "Vs"))) 2) ;; ── predsort/3 ──────────────────────────────────────────────────── (define pl-adv-ps-env-1 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-adv-db (pl-adv-goal "predsort(cmp_num, [], R)" pl-adv-ps-env-1) (pl-mk-trail)) (pl-adv-test! "predsort([]) -> []" (pl-format-term (pl-walk-deep (dict-get pl-adv-ps-env-1 "R"))) "[]") (define pl-adv-ps-env-2 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-adv-db (pl-adv-goal "predsort(cmp_num, [1], R)" pl-adv-ps-env-2) (pl-mk-trail)) (pl-adv-test! "predsort([1]) -> [1]" (pl-format-term (pl-walk-deep (dict-get pl-adv-ps-env-2 "R"))) ".(1, [])") (define pl-adv-ps-env-3 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-adv-db (pl-adv-goal "predsort(cmp_num, [3,1,2], R)" pl-adv-ps-env-3) (pl-mk-trail)) (pl-adv-test! "predsort([3,1,2]) -> [1,2,3]" (pl-format-term (pl-walk-deep (dict-get pl-adv-ps-env-3 "R"))) ".(1, .(2, .(3, [])))") (define pl-adv-ps-env-4 {:R (pl-mk-rt-var "R")}) (pl-solve-once! pl-adv-db (pl-adv-goal "predsort(cmp_num, [3,1,2,1,3], R)" pl-adv-ps-env-4) (pl-mk-trail)) (pl-adv-test! "predsort([3,1,2,1,3]) dedup -> [1,2,3]" (pl-format-term (pl-walk-deep (dict-get pl-adv-ps-env-4 "R"))) ".(1, .(2, .(3, [])))") ;; ── Runner ───────────────────────────────────────────────────────── (define pl-advanced-tests-run! (fn () {:failed pl-adv-test-fail :passed pl-adv-test-pass :total pl-adv-test-count :failures pl-adv-test-failures}))