;; lib/minikanren/run.sx — Phase 3: drive a goal + reify the query var.
;;
;; reify-name N        — make the canonical "_.N" reified symbol.
;; reify-s term rs     — walk term in rs, add a mapping from each fresh
;;                       unbound var to its _.N name (left-to-right order).
;; reify q s           — walk* q in s, build reify-s, walk* again to
;;                       substitute reified names in.
;; run-n n q-name g... — defmacro: bind q-name to a fresh var, conj goals,
;;                       take ≤ n answers from the stream, reify each
;;                       through q-name. n = -1 takes all (used by run*).
;; run*                — defmacro: (run* q g...) ≡ (run-n -1 q g...)
;; run                 — defmacro: (run n q g...) ≡ (run-n n q g...)
;;                       The two-segment form is the standard TRS API.

(define reify-name (fn (n) (make-symbol (str "_." n))))

(define
  reify-s
  (fn
    (term rs)
    (let
      ((w (mk-walk term rs)))
      (cond
        ((is-var? w) (extend (var-name w) (reify-name (len rs)) rs))
        ((mk-list-pair? w) (reduce (fn (acc a) (reify-s a acc)) rs w))
        (:else rs)))))

(define
  reify
  (fn
    (term s)
    (let
      ((w (mk-walk* term s)))
      (let ((rs (reify-s w (empty-subst)))) (mk-walk* w rs)))))

(defmacro
  run-n
  (n q-name &rest goals)
  (quasiquote
    (let
      (((unquote q-name) (make-var)))
      (map
        (fn (s) (reify (unquote q-name) s))
        (stream-take
          (unquote n)
          ((mk-conj (splice-unquote goals)) empty-s))))))

(defmacro
  run*
  (q-name &rest goals)
  (quasiquote (run-n -1 (unquote q-name) (splice-unquote goals))))

(defmacro
  run
  (n q-name &rest goals)
  (quasiquote (run-n (unquote n) (unquote q-name) (splice-unquote goals))))
