12

Clojure 有大量用于处理命名空间和 java 包导入的函数/宏。据我(有限的)理解,命名空间的设置可以被认为是 clojure 进程(repl)中的状态。

在 REPL 会话中迭代工作时,尤其是在(重新)加载源文件时,我会发现很容易混淆 - 通常是当我在命名空间配置中犯了错误或语法错误时。其他时候,我想尝试重构命名空间/别名/引用过滤器,但如果不重新启动 REPL,就无法轻松退出现有命名空间状态。

例如,我希望能够检查点命名空间配置 - 例如在代码主体加载到 repl 之后 - 然后在尝试在 REPL 导入的一些库之后回到那个“干净的石板”,这样我就可以立即测试一个源文件,该文件将该库中过滤的方法子集作为 ns 宏的一部分导入。

人们可以推荐保存和恢复命名空间配置的方法吗?

4

3 回答 3

10

我确定这有问题,因为我只是在回答这个问题时写了它,但我看到自己在我的项目中使用它,当然。只需 :import 它(将它放在项目中自己的文件中)并自由使用它。

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

首先,像这样保存你的世界的状态(你想回到的那个):

(def *save* (save-world))

然后做任何你想做的事——实验。当您准备好回到以前的状态时:

(destroy-world-but '*save*)
(restore-world *save*)

你应该很高兴去!

(希望这行得通!对我有用——如果有问题请告诉我。我相信也有更好的方法来做到这一点,但这行得通,这就是我今晚走了多远。我确定我会修改的。)

于 2010-08-14T02:19:46.697 回答
6

这并不总是有效。您可以使用 将 Vars 从命名空间中删除ns-unmap,但其他代码段可能仍保留对这些定义的引用。

Clojure,因为它基于 JVM,所以没有像某些 Common Lisp 或 Scheme 实现那样的“内存映像”的概念。

于 2010-08-14T16:10:13.187 回答
1

DMTCP 可能以笨拙的方式完成这项工作。Google on DMTCP:分布式多线程检查点。我用它来检查交互式 OCaml 程序。

于 2011-04-03T00:29:05.610 回答