;; https://srfi.schemers.org/srfi-247/srfi-247.html
(defn syntactic-monad [env name parameters args]
  (cond (and (symbol? (first args))
             (not (contains? env (first args)))
             (= #'clojure.core/letfn (resolve (first args))))
        `(~(first args)
          [~@(for [[n & body] (first (rest args))
                   :let [bodies (if (vector? (first body))
                                  (list body)
                                  body)]]
               `(~n ~@(for [body bodies]
                        (cons
                         (into parameters (first body))
                         (rest body)))))]
           ~@(rest (rest args)))
        (and (symbol? (first args))
             (not (contains? env (first args)))
             (= #'clojure.core/fn (resolve (first args))))
        (let [[maybe-name body] (if (symbol? (second args))
                                  [(second args) (rest (rest args))]
                                  [nil (rest args)])
              bodies (if (vector? (first body))
                       (list body)
                       body)]
          `(~(first args)
            ~@maybe-name
            ~@(for [body bodies]
                (cons
                 (into parameters (first body))
                 (rest body)))))
        :else
        (if (vector? (second args))
          `(let ~(second args)
             (~(first args)
              ~@parameters
              ~@(rest (rest args))))
          `(~(first args)
            ~@parameters
            ~@(rest (rest args))))))

(defmacro define-syntactic-monad [name & parameters]
  `(defmacro ~name [& args#]
     (syntactic-monad ~'&env '~name '~(vec parameters) args#)))

(define-syntactic-monad $ prog a b c)


(($ fn [w]
    (if (> a prog)
      ($ recur [prog (inc prog)] w)
      ($ vector w)))
 1 2 3 4 :foo)

Generated At 2024-01-02T16:38:00-0800 original