;; lib/minikanren/project.sx — Phase 5 piece B: `project`. ;; ;; (project (x y) g1 g2 ...) ;; — rebinds each named var to (mk-walk* var s) within the body's ;; lexical scope, then runs the conjunction of the body goals on ;; the same substitution. Use to escape into regular SX (arithmetic, ;; string ops, host predicates) when you need a ground value. ;; ;; If any of the projected vars is still unbound at this point, the body ;; sees the raw `(:var NAME)` term — that is intentional and lets you ;; mix project with `(== ground? var)` patterns or with conda guards. ;; ;; Hygiene: substitution parameter is gensym'd so it doesn't capture user ;; vars (`s` is a popular relation parameter name). (defmacro project (vars &rest goals) (let ((s-sym (gensym "proj-s-"))) (quasiquote (fn ((unquote s-sym)) ((let (unquote (map (fn (v) (list v (list (quote mk-walk*) v s-sym))) vars)) (mk-conj (splice-unquote goals))) (unquote s-sym))))))