;; lib/minikanren/conda.sx — Phase 5 piece A: `conda`, the soft-cut.
;;
;;   (conda (g0 g ...) (h0 h ...) ...)
;;     — first clause whose head g0 produces ANY answer wins; ALL of g0's
;;       answers are then conj'd with the rest of that clause; later
;;       clauses are NOT tried.
;;     — differs from condu only in not wrapping g0 in onceo: condu
;;       commits to the SINGLE first answer, conda lets the head's full
;;       answer-set flow into the rest of the clause.
;;       (Reasoned Schemer chapter 10; Byrd 5.3.)

(define
  conda-try
  (fn
    (clauses s)
    (cond
      ((empty? clauses) mzero)
      (:else
        (let
          ((cl (first clauses)))
          (let
            ((head-goal (first cl)) (rest-goals (rest cl)))
            (let
              ((peek (stream-take 1 (head-goal s))))
              (if
                (empty? peek)
                (conda-try (rest clauses) s)
                (mk-bind (head-goal s) (mk-conj-list rest-goals))))))))))

(defmacro
  conda
  (&rest clauses)
  (quasiquote
    (fn
      (s)
      (conda-try
        (list
          (splice-unquote
            (map
              (fn (cl) (quasiquote (list (splice-unquote cl))))
              clauses)))
        s))))
