Idiomatic clojure for progress reporting?

后端 未结 4 2065
醉酒成梦
醉酒成梦 2020-12-13 00:50

How should I monitor the progress of a mapped function in clojure?

When processing records in an imperative language I often print a message every so often to indica

4条回答
  •  感动是毒
    2020-12-13 01:09

    I don't know of any existing ways of doing that, maybe it would be a good idea to browse clojure.contrib documentation to look if there's already something. In the meantime, I've looked at your example and cleared it up a little bit.

    (defn report [cnt]
      (when (even? cnt)
        (println "Done" cnt)))
    
    (defn report-progress []
      (let [aseq (range 10)]
        (doall (map report (take (count aseq) (iterate inc 1))))
        aseq))
    

    You're heading in the right direction, even though this example is too simple. This gave me an idea about a more generalized version of your report-progress function. This function would take a map-like function, the function to be mapped, a report function and a set of collections (or a seed value and a collection for testing reduce).

    (defn report-progress [m f r & colls]
      (let [result (apply m
                     (fn [& args]
                       (let [v (apply f args)]
                         (apply r v args) v))
                     colls)]
        (if (seq? result)
          (doall result)
          result)))
    

    The seq? part is there only for use with reduce which doesn't necessarily returns a sequence. With this function, we can rewrite your example like this:

    user> 
    (report-progress
      map
      (fn [_ v] v)
      (fn [result cnt _]
        (when (even? cnt)
          (println "Done" cnt)))
      (iterate inc 1)
      (range 10))
    
    Done 2
    Done 4
    Done 6
    Done 8
    Done 10
    (0 1 2 3 4 5 6 7 8 9)
    

    Test the filter function:

    user> 
    (report-progress
      filter
      odd?
      (fn [result cnt]
        (when (even? cnt)
          (println "Done" cnt)))
      (range 10))
    
    Done 0
    Done 2
    Done 4
    Done 6
    Done 8
    (1 3 5 7 9)
    

    And even the reduce function:

    user> 
    (report-progress
      reduce
      +
      (fn [result s v]
        (when (even? s)
          (println "Done" s)))
      2
      (repeat 10 1))
    
    Done 2
    Done 4
    Done 6
    Done 8
    Done 10
    12
    

提交回复
热议问题