问题
Clojure has a large number functions/macros for working with namespaces and java package imports. To my (limited) understanding the set up of namespaces can be considered state in a clojure process (repl).
When working iteratively at a REPL session, especially when source files are (re)-loaded, I can find it easy to get confused - often when I make a mistake or syntax error in namespace configuration. Other times I want to try out refactoring namespaces/aliases/reference filters but can't easily back out of existing namespace state without restarting the REPL.
For example I would like to be able to checkpoint namespace configuration - such as after the main body of code is loaded at the repl - then get back to that "clean-slate" after trying out some library imported at the REPL so that I can immediately test a source file that imports a filtered subset of methods in that library as part of the ns macro.
Can people recommend ways to save and restore namespace configuration?
回答1:
I'm sure there's something wrong with this, as I just wrote it in answer to this question, but I see myself using this in my projects, for sure. Just :import it (have it in its own file in your project) and use it liberally.
(ns world)
(defn save-world
[]
(let [syms (filter identity (distinct (for [i (ns-map *ns*)] (first i))))]
(for [i syms]
(vector i
(ns-resolve *ns* i)))))
(defn destroy-world-but
[saved]
(let [syms (filter identity (distinct (for [i (ns-map *ns*)] (first i))))]
(for [i syms]
(if-not (or (= (ns-resolve *ns* i) (ns-resolve *ns* saved))
(= (ns-resolve *ns* i) (ns-resolve *ns* 'restore-world))
(= (ns-resolve *ns* i) (ns-resolve *ns* '*ns*)))
(ns-unmap *ns* i)))))
(defn restore-world
[saved]
(clojure.core/map
#(intern *ns* (clojure.core/first %) (clojure.core/second %))
saved))
First, save a the state of your world (the one you want to go back to) like this:
(def *save* (save-world))
Then do whatever you want–experiment. When you're ready to go back to your former state:
(destroy-world-but '*save*)
(restore-world *save*)
And you should be good to go!
(Hope this works! Was working for me–please let me know if there's a problem. I'm sure there's a better way to do this, too, but this works and it's how far I got tonight. I'm sure I'll revise.)
回答2:
This won't always work. You can remove Vars from a namespace with ns-unmap
, but other pieces of code may still hold references to those definitions.
Clojure, because it is based on the JVM, has no concept of a "memory image" like some Common Lisp or Scheme implementations.
回答3:
DMTCP might do the job in a clumsy way. Google on DMTCP: Distributed MultiThreaded CheckPointing. I use it to checkpoint interactive OCaml programs.
来源:https://stackoverflow.com/questions/3480377/clojure-namespace-management-is-there-a-way-to-save-and-restore-the-state-of-c