retrying something 3 times before throwing an exception - in clojure

后端 未结 4 1312
旧时难觅i
旧时难觅i 2021-02-10 04:58

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         


        
4条回答
  •  自闭症患者
    2021-02-10 05:29

    Here's one approach:

    (defmacro retry
      "Evaluates expr up to cnt + 1 times, retrying if an exception
      is thrown. If an exception is thrown on the final attempt, it
      is allowed to bubble up."
      [cnt expr]
      (letfn [(go [cnt]
                (if (zero? cnt)
                  expr
                  `(try ~expr
                        (catch Exception e#
                          (retry ~(dec cnt) ~expr)))))]
        (go cnt)))
    

    Example from the REPL:

    user> (retry 2 (do (println :foo) (throw (RuntimeException. "foo"))))
    :foo
    :foo
    :foo
    ; Evaluation aborted.
    

    (Passing 2 to retry asks expr to be retried twice it if fails the first time round, for a total of three attempts. Three :foos are printed, because the println occurs before the throw in the do form passed to retry. The final ; Evaluation aborted. means an exception was thrown.)

    Also, about the for loop from your snippet:

    If you try looping over a longer range (replace (range 3) with (range 10), say), the output will end after i reaches 3. Also, if you put in a println before the form which throws the exception, it will of course print out whatever you pass to it; if the println occurs after the exception-throwing form, there will be no printout. In any case, at most three calls to println will be executed (assuming an exception is thrown on every iteration).

提交回复
热议问题