Files
rose-ash/lib/minikanren/project.sx
giles d61b355413
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 56s
mk: phase 5B — project, escape into host SX
(project (vars ...) goal ...) defmacro walks each named var via mk-walk*,
rebinds them in the body's lexical scope, then mk-conjs the body goals on
the same substitution. Hygienic — gensym'd s-param so user vars survive.

Lets you reach into host SX for arithmetic, string ops, anything that
needs a ground value: (project (n) (== q (* n n))), (project (s)
(== q (str s \"!\"))), and so on.

6 new tests, 194/194 cumulative.
2026-05-07 23:27:16 +00:00

26 lines
1012 B
Plaintext

;; 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))))))