2011-08-30 114 views
9

我有一个来自我正在阅读的文件的传入惰性流线,tail-seq(对contrib - now!),我想要一个接一个地处理这些行,带有几个“监听函数”行动取决于行中的重新seq-hit(或其他事物)。一个参数,许多函数

我试过如下:

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

,它按预期工作。但是,代码中存在很多代码重复和其他错误,更新代码很无聊。

的一个重要步骤,似乎是许多功能应用到一个说法,即

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

并使用它的枯燥,容易出错DO语句。

我已尝试以下看似聪明的做法:

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

但这只能使

(nil) (nil) 

有咬我肯定lazyiness或第一类函数,但我在哪里放应用?

我也对这个问题采取了截然不同的方法,但这似乎是一个相当理智的方式。现在,宏/多方法似乎是过度/错误的。

回答

10

制作出一组功能的单一功能使用相同的参数调用与核心功能juxt来完成:

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

结合juxtpartial是非常有用的:

 
(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

这是非常优雅的,也给了我更深入的见解Clojure(就像上面的答案)。谢谢你,亚历克斯! – claj

+1

@claj你很善良。如果您想进一步提高抽象级别,请进行一些小改动,并将第二个参数设置为监听器本身是一个用logstr调用的函数。这使基于输入匹配的不同动作成为可能。那时我们基本上已经改造了一种多方法。作为第一类实体的函数可以实现非常强大的抽象! –

9

您需要更改

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

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

在第一个版本,listen-line最终使用符号info-listenerdebug-listener自己是因为引用的功能。符号实现clojure.lang.IFn(Clojure函数调用后面的接口)就像关键字一样,也就是说,如果应用于不是地图的东西,它们会以类似地图的参数(实际上是clojure.lang.ILookup)查找自己,并返回nil

另请注意,您需要将listen-line的正文包装在dorun中,以确保它实际得到执行(因为map返回惰性序列)。更重要的是,切换到doseq

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

更好的更好,但改用'juxt ':((应用juxt listener-collection)logstr)' – amalloy

+0

谢谢Michal帮忙用清单清理我的错误!我认为juxt对我来说是最习惯的解决方案 - 虽然上面还有amalloy,下面的Alex也是这个建议! – claj