2011-08-30 49 views
9

Tôi có một dòng suối lười đến từ một tệp mà tôi đang đọc với tail-seq (để đóng góp - bây giờ!) Và tôi muốn xử lý các dòng sau một với một vài "hàm listener" hành động tùy thuộc vào lần truy cập lại (hoặc những thứ khác) trong các dòng.Một đối số, nhiều chức năng

tôi thử như sau:

(defn info-listener [logstr] 
    (if (re-seq #"INFO" logstr) (println "Got an INFO-statement"))) 

(defn debug-listener [logstr] 
    (if (re-seq #"DEBUG" logstr) (println "Got a DEBUG-statement"))) 

(doseq [line (tail-seq "/var/log/any/java.log")] 
    (do (info-listener logstr) 
     (debug-listener logstr))) 

và nó hoạt động như mong đợi. Tuy nhiên, có rất nhiều mã trùng lặp và các lỗi khác trong mã, và nó nhàm chán để cập nhật mã.

Một bước quan trọng có vẻ là để áp dụng nhiều chức năng để một đối số, tức là

(listen-line line '(info-listener debug-listener)) 

và sử dụng rằng thay vì nhàm chán và dễ bị lỗi do-tuyên bố.

Tôi đã thử các cách tiếp cận thông minh dường như sau:

(defn listen-line [logstr listener-collection] 
    (map #(% logstr) listener-collection)) 

nhưng điều này chỉ làm cho

(nil) (nil) 

có chức năng lớp lazyiness hoặc đầu tiên cắn tôi chắc chắn, nhưng nơi nào tôi đặt ứng dụng?

Tôi cũng mở ra một cách tiếp cận hoàn toàn khác cho vấn đề, nhưng điều này có vẻ là một cách khá lành mạnh để bắt đầu. Macro/đa phương pháp có vẻ là quá mức/sai cho đến bây giờ.

Trả lời

10

Làm một chức năng duy nhất ra khỏi một nhóm các chức năng được gọi với đối số tương tự có thể được thực hiện với các chức năng cốt lõi juxt:

 
=>(def juxted-fn (juxt identity str (partial/100))) 
=>(juxted-fn 50) 
[50 "50" 2] 

Kết hợp juxt với partial có thể rất hữu ích:

 
(defn listener [re message logstr] 
    (if (re-seq re logstr) (println message))) 
 
(def juxted-listener 
    (apply juxt (map (fn [[re message]] (partial listner re message)) 
    [[#"INFO","Got INFO"], 
     [#"DEBUG", "Got DEBUG"]])) 
 
(doseq [logstr ["INFO statement", "OTHER statement", "DEBUG statement"]] 
    (juxted-listener logstr)) 

+0

Điều này rất thanh lịch và cũng đã cho tôi những hiểu biết sâu sắc hơn về Clojure (giống như câu trả lời ở trên). Cảm ơn, Alex! – claj

+1

@claj bạn rất tử tế. Nếu bạn muốn lấy mức độ trừu tượng hơn nữa bạn thực hiện một thay đổi nhỏ và có đối số thứ hai cho người nghe chính nó là một hàm được gọi với logstr. Điều đó cho phép các hành động khác nhau dựa trên kết hợp đầu vào. Vào thời điểm đó, chúng tôi đã cơ bản tái tạo một đa phương thức. Các hàm như các thực thể lớp đầu tiên cho phép trừu tượng hóa mạnh mẽ! –

9

Bạn cần thay đổi

(listen-line line '(info-listener debug-listener)) 

để

(listen-line line [info-listener debug-listener]) 

Trong phiên bản đầu tiên, listen-line kết thúc bằng cách sử dụng những biểu tượng info-listenerdebug-listener tự như các chức năng vì sự trích dẫn. Biểu tượng thực hiện clojure.lang.IFn (giao diện ẩn sau hàm gọi hàm Clojure) như từ khóa, nghĩa là chúng trông giống như đối số giống như bản đồ (thực tế là clojure.lang.ILookup) và trả lại nil nếu áp dụng cho một thứ không phải là bản đồ.

Cũng lưu ý rằng bạn cần phải quấn phần thân của listen-line trong dorun để đảm bảo nó thực sự được thực thi (như map trả về một chuỗi lười). Hơn thế nữa, chuyển sang doseq:

(defn listen-line [logstr listener-collection] 
    (doseq [listener listener-collection] 
    (listener logstr))) 
+3

Better tốt hơn nữa, chuyển sang 'juxt ':' ((áp dụng juxt listener-collection) logstr) ' – amalloy

+0

cảm ơn Michal vì đã giúp bạn dọn dẹp sai lầm trong danh sách!Tôi nghĩ rằng juxt là giải pháp thành ngữ nhất cho tôi mặc dù - cảm ơn bạn amalloy ở trên và Alex dưới đây cũng cho đề nghị đó! – claj

Các vấn đề liên quan