Question

I wrote this helper function:

(defn iterate-converge
  "Returns the value from calling (f x) some number of times, until
  `x` changes by less than a tolerance, `tol`. Will not execute more
  than `b` (e.g. bailout) times."
  [f x0 tol b]
  (loop [f f x x0 tol tol b b i 0]
    (if (>= i b)
      (throw (ex-info "Failed to converge"
                      {:type ::failed-to-converge :tol tol :b b}))
      (let [x' (f x)]
        (if (< (abs (- x x')) tol)
          x'
          (recur f x' tol b (inc i)))))))

Depending upon the parameters, this can take a significant amount of time. I'd like the function report on its progress. I don't want it to be tied to console output (e.g. println).

My current ideas:

  1. Add a callback function as a parameter. Call it for each pass through. This allows for push notification.
  2. Add an atom as a parameter. Update it for each pass through. This would allow for polling or push notification by using add-watch.
  3. Add a core.async channel as a parameter. Similar to (1) above but may give better multicore performance.

What would you do and why?

Was it helpful?

Solution

Just make it return a lazy sequence of candidate answers. Then you can iterate through them at your leisure, stopping whenever the answer is acceptable, or when you decide it's taken too long and you want to give up.

OTHER TIPS

Personally I would rank these options in reverse order, #3 being most flexible because then you can handle the output in more interesting (and fun) ways.

If you are looking for more options, I can recommend the Narrator library as a way to accurately produce periodic reports of long running processes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top