Clojure namespace management - Is there a way to save and restore the state of clojure repl namespaces, imports etc.?

笑着哭i 提交于 2019-12-20 10:39:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!