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