Last active
December 18, 2015 17:09
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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