2010-08-13 11 views
11

Clojure có một số lượng lớn chức năng/macro để làm việc với không gian tên và nhập gói java. Để sự hiểu biết của tôi (hạn chế) việc thiết lập các không gian tên có thể được coi là trạng thái trong một quá trình clojure (repl).Quản lý không gian tên Clojure - Có cách nào để lưu và khôi phục trạng thái không gian tên thay thế clojure, nhập khẩu, v.v. không?

Khi làm việc lặp lại tại phiên REPL, đặc biệt khi tệp nguồn được tải lại, tôi có thể dễ dàng nhầm lẫn - thường khi tôi mắc lỗi hoặc lỗi cú pháp trong cấu hình không gian tên. Lần khác, tôi muốn thử tái cấu trúc không gian tên/bí danh/bộ lọc tham chiếu nhưng không thể dễ dàng thoát khỏi trạng thái không gian tên hiện tại mà không cần khởi động lại REPL. Ví dụ: Tôi muốn có thể cấu hình không gian tên điểm kiểm tra - chẳng hạn như sau khi phần chính của mã được tải tại repl - sau đó quay trở lại "slate clean" đó sau khi thử một số thư viện được nhập vào REPL để tôi có thể kiểm tra ngay lập tức tệp nguồn nhập một tập con được lọc của các phương thức trong thư viện đó như là một phần của macro ns.

Mọi người có thể đề xuất các cách lưu và khôi phục cấu hình không gian tên không?

+1

Điều này nghe giống như chức năng _save-world_ mà nhiều triển khai Common Lisp mang theo. – Greg

+0

Chắc chắn là có thể, bằng cách sử dụng (clojure.lang.Namespace/all) và .getMappings, nhưng tôi không thể tìm thấy bất kỳ dấu hiệu nào cho thấy bất kỳ ai đã thực hiện nó. – dreish

Trả lời

10

Tôi chắc chắn có điều gì đó sai với điều này, vì tôi vừa viết câu trả lời cho câu hỏi này, nhưng tôi thấy bản thân mình đang sử dụng điều này trong các dự án của mình. Chỉ cần: nhập nó (có nó trong tập tin riêng của nó trong dự án của bạn) và sử dụng nó một cách tự do.

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

Đầu tiên, tiết kiệm một tình trạng thế giới của bạn (một trong những bạn muốn quay trở lại) như thế này:

(def *save* (save-world)) 

Sau đó làm bất cứ điều gì bạn muốn, thí nghiệm. Khi bạn đã sẵn sàng quay trở lại trạng thái cũ của mình:

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

Và bạn nên làm tốt! Làm việc cho tôi - hãy cho tôi biết nếu có vấn đề gì. Tôi chắc chắn có một cách tốt hơn để làm điều này, nhưng nó hoạt động và nó đã đến mức tối nay tôi có được bao nhiêu. Tôi '. m chắc chắn tôi sẽ sửa đổi.)

6

Điều này sẽ không luôn hoạt động. Bạn có thể xóa Vars khỏi không gian tên bằng ns-unmap, nhưng các phần mã khác vẫn có thể giữ tham chiếu đến các định nghĩa đó.

Clojure, bởi vì nó dựa trên JVM, không có khái niệm về "hình ảnh bộ nhớ" như một số triển khai Common Lisp hoặc Scheme.

+0

Cảnh báo được thực hiện tốt. Vì vậy, tôi có thể gặp rất nhiều rắc rối nếu tôi cố gắng tiết kiệm và khôi phục trạng thái của một ứng dụng chạy dài phức tạp chẳng hạn. Nhưng đối với các trường hợp sử dụng đơn giản của các chức năng cần thiết/bí danh tại một phiên repl duy nhất tôi nghi ngờ tôi có lẽ ok làm một cái gì đó giống như những gì Issac cho thấy dưới đây. –

1

DMTCP có thể thực hiện công việc theo cách vụng về. Google trên DMTCP: CheckPointing MultiThreaded được phân phối. Tôi sử dụng nó để kiểm tra các chương trình OCAMl tương tác.