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