Skip to content

Instantly share code, notes, and snippets.

@brandonbloom
Last active November 13, 2017 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brandonbloom/55a4fae8a5e348f0c499232a43fbac43 to your computer and use it in GitHub Desktop.
Save brandonbloom/55a4fae8a5e348f0c499232a43fbac43 to your computer and use it in GitHub Desktop.
;;; Handlers.
;; Approximates effect handlers without unwinding the stack.
;; Captures thread bindings so as to avoid "open recursion" between handlers.
;; Also binds `super` to bubble effect up to the next handler.
(def ^:dynamic super)
(defn bind-handler [var f]
(let [bindings (assoc (get-thread-bindings) #'super @var)]
(fn [& args]
(apply with-bindings* bindings f args))))
(defn with-handler* [handler f]
(let [h (into {} (for [[var f] handler]
[var (bind-handler var f)]))]
(with-bindings* h f)))
(defmacro with-handler [handler & body]
`(with-handler* ~handler (fn [] ~@body)))
(defmacro handler [& impls]
(let [impls (conform! (s/* (s/cat :var symbol?
:methods (s/* seq?)))
impls)]
(into {}
(for [{:keys [var methods]} impls]
[(list 'var var) `(fn ~@methods)]))))
(defmacro defhandler [name & impls]
`(def ~name (handler ~@impls)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment