Skip to content

Instantly share code, notes, and snippets.

@aphyr
Created January 20, 2016 03:14
Show Gist options
  • Select an option

  • Save aphyr/a81825ab80656679db78 to your computer and use it in GitHub Desktop.

Select an option

Save aphyr/a81825ab80656679db78 to your computer and use it in GitHub Desktop.
Recur from within catch block
(defrecord Retry [bindings])
(defmacro with-retry
"It's really fucking inconvenient not being able to recur from within (catch)
expressions. This macro wraps its body in a (loop [bindings] (try ...)).
Provides a (retry & new bindings) form which is usable within (catch) blocks:
when this form is returned by the body, the body will be retried with the new
bindings."
[initial-bindings & body]
(assert (vector? initial-bindings))
(assert (even? (count initial-bindings)))
(let [bindings-count (/ (count initial-bindings) 2)
body (walk/prewalk (fn [form]
(if (and (list? form)
(= 'retry (first form)))
(do (assert (= bindings-count
(count (rest form))))
`(Retry. [~@(rest form)]))
form))
body)
retval (gensym 'retval)]
`(loop [~@initial-bindings]
(let [~retval (try ~@body)]
(if (instance? Retry ~retval)
(recur ~@(->> (range bindings-count)
(map (fn [i] `(nth (.bindings ~retval) ~i)))))
~retval)))))
(->> (with-retry [x 0 y 0]
[(/ 1 x) y]
(catch Exception e
(retry (inc x) (inc y))))
quote macroexpand pprint)
(loop*
[x 0 y 0]
(clojure.core/let
[retval869
(try
[(/ 1 x) y]
(catch Exception e (user.Retry. [(inc x) (inc y)])))]
(if
(clojure.core/instance? user.Retry retval869)
(recur
(clojure.core/nth (.bindings retval869) 0)
(clojure.core/nth (.bindings retval869) 1))
retval869)))
(with-retry [x 0 y 0]
[(/ 1 x) y]
(catch Exception e
(retry (inc x) (inc y))))
; => [1 1]
@divs1210
Copy link
Copy Markdown

divs1210 commented Jul 27, 2022

thanks!

It's missing (require '[clojure.walk :as walk]) at the top, but otherwise works beautifully!

@aphyr
Copy link
Copy Markdown
Author

aphyr commented Oct 11, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment