Skip to content

Instantly share code, notes, and snippets.

@rctay
Last active December 15, 2015 00:59
Show Gist options
  • Save rctay/5176524 to your computer and use it in GitHub Desktop.
Save rctay/5176524 to your computer and use it in GitHub Desktop.
binding based on Vars in a namespace
(defmacro binding-ns
"Like binding, but bindings are based on all publics in ns."
[from-ns & body]
(let [ns-vars (fn [-ns]
; fnext to get var from ns-publics name-var pairs
(filter #(:dynamic (meta (fnext %)))
(ns-publics -ns)))
var-ize (fn [from-name-vars]
(loop [ret {} from-name-vars (seq from-name-vars)]
(if-let [[name from-var] (first from-name-vars)]
(recur (assoc ret
from-var
(if-let [to-var (resolve name)]
to-var
(var-get from-var)))
(next from-name-vars))
ret)))]
`(with-bindings* ~(var-ize (ns-vars from-ns)) (fn [] ~@body))))
user=> (def ^:dynamic mul)
#'user/mul
user=> (def ^:dynamic mul-inv)
#'user/mul-inv
user=> (defn test-mul [a b] (mul a b))
#'user/test-mul
user=> (defn test-mul-inv [a] (test-mul a (mul-inv a)))
#'user/test-mul-inv
user=> (ns math)
nil
math=> (defn mod-mul [m a b] (mod (* a b) m))
#'math/mod-mul
math=> (defn expt [a b] (apply * (repeat b a)))
#'math/expt
math=> user=> (defn mod-expt [m b a]
(reduce (fn [c _] (mod (* c a) m)) 1 (range b)))
#'math/mod-expt
math=> (ns mod5)
nil
mod5=> (def mul (partial math/mod-mul 5))
#'mod5/mul
mod5=> (def mul-inv (partial math/mod-expt 5 3))
#'mod5/mul-inv
mod5=> (ns mod7)
nil
mod7=> (def mul (partial math/mod-mul 7))
#'mod7/mul
mod7=> (def mul-inv (partial math/mod-expt 7 5))
#'mod7/mul-inv
mod7=> (ns user)
nil
user=> (binding-ns mod5 (println (test-mul 2 3) (test-mul-inv 2)))
1 1
nil
user=> (binding-ns mod7 (println (test-mul 2 3) (test-mul-inv 2)))
6 1
nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment