Zustand der Kompilierung zwischen verschachtelten Makros in Clojure übergeben

Ich versuche, ein Makro zu schreiben, das sowohl global als auch verschachtelt verwendet werden kann:

;;; global:
(do-stuff 1)

;;; nested, within a "with-context" block:
(with-context {:foo :bar}
  (do-stuff 2)
  (do-stuff 3))

Wenn verschachtelt verwendet,do-stuff sollte Zugriff auf @ hab{:foo :bar} gesetzt vonwith-context.

Ich konnte es so implementieren:

(def ^:dynamic *ctx* nil)

(defmacro with-context [ctx & body]
  `(binding [*ctx* ~ctx]
     (do ~@body)))

(defmacro do-stuff [v]
  `(if *ctx*
     (println "within context" *ctx* ":" ~v)
     (println "no context:" ~v)))

Allerdings habe ich versucht, das @ zu verschiebif innerhalbdo-stuff von der Laufzeit bis zur Kompilierung, denn obdo-stuff wird aus dem Körper von @ aufgerufwith-context oder global ist eine Information, die bereits zur Kompilierungszeit verfügbar ist.

Leider konnte ich keine Lösung finden, da verschachtelte Makros in mehreren "Makro-Erweiterungsläufen" erweitert zu werden scheinen, sodass die dynamische Bindung von*ctx* (wie in @ gesetzwith-context) ist nicht mehr verfügbar, wenndo-stuff wird erweitert. Das funktioniert also nicht:

(def ^:dynamic *ctx* nil)

(defmacro with-context [ctx & body]
  (binding [*ctx* ctx]
    `(do ~@body)))

(defmacro do-stuff [v]
  (if *ctx*
    `(println "within context" ~*ctx* ":" ~v)
    `(println "no context:" ~v)))

Haben Sie eine Idee, wie Sie dies erreichen können?

Oder ist mein Ansatz total verrückt und es gibt ein Muster, wie man einen Zustand so von einem Makro zu einem verschachtelten übergibt?

BEARBEITE:

Der Körper vonwith-context sollte mit beliebigen Ausdrücken arbeiten können, nicht nur mitdo-stuff (oder andere kontextsensitive Funktionen / Makros). So etwas sollte also auch möglich sein:

(with-context {:foo :bar}
  (do-stuff 2)
  (some-arbitrary-function)
  (do-stuff 3))

(Mir ist bewusst, dasssome-arbitrary-function handelt von Nebenwirkungen, es könnte zum Beispiel etwas in eine Datenbank schreiben.)

Antworten auf die Frage(6)

Ihre Antwort auf die Frage