;; lib/minikanren/unify.sx — Phase 1 + cons-cell extension. ;; ;; miniKanren-on-SX, built on lib/guest/match.sx. The kit ships the heavy ;; lifting (walk-with, unify-with, occurs-with, extend, empty-subst, ;; mk-var/is-var?/var-name); this file supplies a miniKanren-shaped cfg ;; and a thin public API. ;; ;; Term shapes: ;; logic var : (:var NAME) — kit's mk-var ;; cons cell : (:cons HEAD TAIL) — for relational programming ;; (built by mk-cons; lets relations decompose lists by ;; head/tail without proper improper pairs in the host) ;; native list : SX list (a b c) — also unifies pair-style: ;; args = (head, tail) so (1 2 3) ≡ (:cons 1 (:cons 2 (:cons 3 ()))) ;; atom : number / string / symbol / boolean / nil / () ;; ;; Substitution: SX dict mapping VAR-NAME → term. Empty = (empty-subst). (define mk-cons (fn (h t) (list :cons h t))) (define mk-cons-cell? (fn (t) (and (list? t) (not (empty? t)) (= (first t) :cons)))) (define mk-cons-head (fn (t) (nth t 1))) (define mk-cons-tail (fn (t) (nth t 2))) (define mk-list-pair? (fn (t) (and (list? t) (not (empty? t)) (not (is-var? t))))) (define mk-list-pair-head (fn (t) :pair)) (define mk-list-pair-args (fn (t) (cond ((mk-cons-cell? t) (list (mk-cons-head t) (mk-cons-tail t))) (:else (list (first t) (rest t)))))) (define mk-cfg {:ctor-head mk-list-pair-head :var? is-var? :ctor? mk-list-pair? :occurs-check? false :var-name var-name :ctor-args mk-list-pair-args}) (define mk-cfg-occurs {:ctor-head mk-list-pair-head :var? is-var? :ctor? mk-list-pair? :occurs-check? true :var-name var-name :ctor-args mk-list-pair-args}) (define empty-s (empty-subst)) (define mk-fresh-counter 0) (define make-var (fn () (begin (set! mk-fresh-counter (+ mk-fresh-counter 1)) (mk-var (str "_." mk-fresh-counter))))) (define mk-var? is-var?) (define mk-walk (fn (t s) (walk-with mk-cfg t s))) (define mk-walk* (fn (t s) (let ((w (mk-walk t s))) (cond ((mk-cons-cell? w) (let ((h (mk-walk* (mk-cons-head w) s)) (tl (mk-walk* (mk-cons-tail w) s))) (cond ((empty? tl) (list h)) ((mk-cons-cell? tl) tl) ((list? tl) (cons h tl)) (:else (mk-cons h tl))))) ((mk-list-pair? w) (map (fn (a) (mk-walk* a s)) w)) (:else w))))) (define mk-unify (fn (u v s) (unify-with mk-cfg u v s))) (define mk-unify-check (fn (u v s) (unify-with mk-cfg-occurs u v s)))