Clojure Управление пространством имен. Есть ли способ сохранить и восстановить состояние Clojure repl namespaces, импорт и т.д.?

Clojure имеет большое количество функций/макросов для работы с пространствами имен и импорта пакетов java. Для моего (ограниченного) понимания установка пространств имен может считаться состоянием в процессе clojure (repl).

При работе итеративно на сеансе REPL, особенно когда исходные файлы (re) -гружены, я могу легко смутить - часто, когда я делаю ошибку или синтаксическую ошибку в конфигурации пространства имен. В других случаях я хочу попробовать рефакторинг пространств имен/псевдонимов/ссылочных фильтров, но не может легко вернуться из существующего состояния пространства имен без перезапуска REPL.

Например, я хотел бы иметь возможность конфигурации пространства имен контрольных точек, например, после загрузки основной части кода в реплику, а затем вернуться к этому "чист-шиферу" после проверки какой-либо библиотеки, импортированной в REPL, таким образом что я могу сразу проверить исходный файл, который импортирует отфильтрованное подмножество методов в этой библиотеке как часть макроса ns.

Могут ли люди рекомендовать способы сохранения и восстановления конфигурации пространства имен?

Ответ 1

Я уверен, что с этим что-то не так, как я только что написал в ответ на этот вопрос, но я вижу, что сам использую это в своих проектах, конечно. Просто: импортируйте его (используйте его в своем собственном файле в своем проекте) и используйте его свободно.

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

И вам должно быть хорошо идти!

(Надеюсь, что это сработает! Работал для меня - пожалуйста, дайте мне знать, если есть проблема. Я уверен, что есть лучший способ сделать это тоже, но это работает, и это как далеко я получил сегодня. конечно, я пересмотрю.)

Ответ 2

Это не всегда будет работать. Вы можете удалить Vars из пространства имен с помощью ns-unmap, но другие фрагменты кода могут содержать ссылки на эти определения.

Clojure, поскольку он основан на JVM, не имеет понятия "образ памяти", например, некоторые общие реализации Lisp или схемы.

Ответ 3

DMTCP может выполнить эту работу неуклюже. Google на DMTCP: распределенная многопоточная проверка. Я использую его для проверок интерактивных программ OCaml.