2010-08-13 4 views
11

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

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

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

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

+1

Это звучит как функция _save-world_, которую несут многие реализации Common Lisp. – Greg

+0

Это должно быть возможно, используя (clojure.lang.Namespace/all) и .getMappings, но я не могу найти никаких указаний на то, что кто-то это сделал. – dreish

ответ

10

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

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

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

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

6

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

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

+0

Предупреждение хорошо приняты. Таким образом, я мог бы столкнуться с большими проблемами, если бы пытался сохранить и восстановить состояние сложного приложения с большим сроком службы. Но для простого использования функций, требуемых/сглаженных на одном сеансе реплики, я подозреваю, что я, вероятно, делаю что-то вроде того, что показывает Исаак ниже. –

1

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

 Смежные вопросы

  • Нет связанных вопросов^_^