retrying something 3 times before throwing an exception - in clojure

clojure

Solution

Similar to Marcyk's answer, but no macro trickery:

(defn retry
  [retries f & args]
  (let [res (try {:value (apply f args)}
                 (catch Exception e
                   (if (zero? retries)
                     (throw e)
                     {:exception e})))]
    (if (:exception res)
      (recur (dec retries) f args)
      (:value res))))

Slightly complicated because you can't `recur` inside a `catch` clause. Note that this takes a function:

(retry 3 (fn [] 
          (println "foo") 
          (if (zero? (rand-int 2))
              (throw (Exception. "foo"))
              2)))
=>
foo ;; one or two or three of these
foo
2

Problem

I don't know how to implement this piece of Python code in Clojure ``` for i in range(3): try: ...... except e: if i == 2: raise e else: continue else: break ``` I wonder why something so simple in Python is so hard in Clojure. I think the difficulty is because Clojure is a functional programming language and thus is not suitable for such an imperative task. This is my attempt: ``` (first (remove #(instance? Exception %) (for [i (range 3)] (try (......) (catch Exception e (if (== i 2) (throw e) e))))))) ``` It is very ugly, and worse, it doesn't work as expected. The for loop is actually evaluated fully instead of lazily (I realized this when I put a println inside). If anyone has a better idea to implement that, please enlighten me.

Original source

Related problems