[英]One argument, many functions
我有一个来自我正在使用tail-seq读取的文件的传入惰性流行(对于contrib - now!)我想要一个接一个地处理这些行,其中有几个“侦听器函数”根据re-seq采取行动-hits(或其他东西)在行中。
我尝试了以下方法:
(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))
并使用它而不是枯燥和容易出错的声明。
我尝试了以下看似聪明的方法:
(defn listen-line [logstr listener-collection]
(map #(% logstr) listener-collection))
但这只会呈现
(nil) (nil)
懒惰或一流的功能肯定会咬我,但我在哪里提出申请?
我也对这个问题采取截然不同的方法,但这似乎是一个非常理智的方式。 宏/多方法现在似乎有点矫枉过正。
使用核心函数juxt
可以使用相同的参数从一组函数中创建单个函数:
=>(def juxted-fn (juxt identity str (partial / 100)))
=>(juxted-fn 50)
[50 "50" 2]
将juxt
与partial
结合juxt
非常有用:
(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))
你需要改变
(listen-line line '(info-listener debug-listener))
至
(listen-line line [info-listener debug-listener])
在第一个版本中,由于引用, listen-line
最终使用符号info-listener
和debug-listener
本身作为函数。 符号实现了clojure.lang.IFn
(Clojure函数调用背后的接口),就像关键字一样,即它们看起来像一个类似map的参数(实际上是一个clojure.lang.ILookup
),并且如果应用于不是a的东西则返回nil
地图。
另请注意,您需要在dorun
包含listen-line
的dorun
以确保它实际执行(因为map
返回一个惰性序列)。 更好的是,切换到doseq
:
(defn listen-line [logstr listener-collection]
(doseq [listener listener-collection]
(listener logstr)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.