Один аргумент, много функций - PullRequest
9 голосов
/ 30 августа 2011

У меня есть входящие ленивые строки потока из файла, который я читаю с помощью tail-seq (для вклада - сейчас!), И я хочу обработать эти строки одну за другой с несколькими "функциями слушателя"", который принимает действие в зависимости от повторных попаданий (или других вещей) в строках.

Я пробовал следующее:

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

, что лень или функции первого класса меня кусают наверняка,но куда мне положить заявку?

Я также открыт для радикально другого подхода к проблеме, но это, кажется, вполне разумный способ начать с.Макросы / мульти методы пока кажутся излишними / неправильными.

Ответы [ 2 ]

10 голосов
/ 31 августа 2011

Создание одной функции из группы функций, вызываемых с одним и тем же аргументом, может быть выполнено с помощью базовой функции juxt: =>(def juxted-fn (juxt identity str (partial / 100))) =>(juxted-fn 50) [50 "50" 2]

Объединение juxt с partial может быть очень полезным: (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))

9 голосов
/ 30 августа 2011

Вам нужно изменить

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

на

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

В первой версии listen-line заканчивается использованием символов info-listener и debug-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)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...