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.