Skip to content

Instantly share code, notes, and snippets.

@mattdenner
Last active December 18, 2015 17:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattdenner/5816745 to your computer and use it in GitHub Desktop.
Save mattdenner/5816745 to your computer and use it in GitHub Desktop.
I stumbled across http://stackoverflow.com/questions/2022911/idiomatic-clojure-for-progress-reporting which talks about reporting progress as you map over a sequence. The original code is included in this gist as https://gist.github.com/mattdenner/5816745#file-original-clj, but I thought it'd be interested to try to refactor this.
; My first attempt would have been my typical approach: wrap the function being used in the map. What I dislike, even though
; this is my current natural (read "first thing I try normally") is that 'reporter' looks more complicated than I'd like, plus
; 'report-progress' knows about the idea of "progress".
(defn reporter
[report-every f]
(fn [val cnt]
(let [rv (f val)]
(and (zero? (mod cnt report-every)) (println "Done" cnt))
val)
))
(defn report-progress
[report-every aseq]
(map (reporter report-every identity)
aseq
(iterate inc 1)))
(doall (report-progress 2 (range 10)))
; Then I read the popular answer (http://stackoverflow.com/a/2023356/207031) which talks about wrapping the *data*. At the
; moment this is my favourite, and it's taught me a lot, because it cleanly separates so much of the behaviour.
(defn progress-reporter
"Returns a function that reports the count every 'report-every' times"
[report-every]
(fn [cnt _]
(and (zero? (mod cnt report-every)) (println "Done" cnt))))
(defn reporting-seq
"Wraps a sequence so that the 'reporter' function is called with the index and value for reporting, but maintains map
behaviour of the inner sequence"
[aseq reporter]
(map-indexed (fn [& args] (apply reporter args) (last args)) aseq))
; Here 'report-progress' knows only about mapping, really, and so this function doesn't have to exist:
; (doall (map identity (reporting-seq (range 10) (progress-reporter 2))))
;
; Which then leads to:
; (doall (map identity (reporting-seq (range 10) (fn [cnt val] (println "Processing:" val)))))
;
; Which has nothing to do with progress!
(defn report-progress
[report-every aseq]
(map identity (reporting-seq aseq (progress-reporter report-every))))
(doall (report-progress 2 (range 10)))
; Here's the original code:
(defn report
[report-every val cnt]
(if (= 0 (mod cnt report-every))
(println "Done" cnt))
val)
(defn report-progress
[report-every aseq]
(map (fn [val cnt]
(report report-every val cnt))
aseq
(iterate inc 1)))
(doall (report-progress 2 (range 10)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment