mybuddymichael
mybuddymichael

Reputation: 1710

How can I recur from a Clojure catch block in a more functional manner?

For an IRC bot I'm writing, I want to keep trying to open a socket, even if there's an UnkownHostException. My first thought was something like this.

(defn open-socket [{:keys [host port] :as connection}]
  (try (java.net.Socket. host port)
    (catch java.net.UnknownHostException _ (recur connection))))

But it doesn't work because you can't recur from a catch block. So instead I settled on something like this:

  (let [socket (promise)
        _ (while (not (realized? socket))
            (try (deliver socket (java.net.Socket. host port))
              (catch java.net.UnknownHostException _)))
        socket @socket]
    ...

And this works, but it's awfully imperative. Is there a more functional way I could be doing this that I can't see?

Upvotes: 5

Views: 374

Answers (2)

Ankur
Ankur

Reputation: 33657

Just add an or:

(defn open-socket [{:keys [host port] :as connection}]
  (or (try (java.net.Socket. host port)
           (catch java.net.UnknownHostException _ nil))
      (recur connection)))

Upvotes: 13

mange
mange

Reputation: 3212

One possibility might be something like this?

(let [make-socket #(try (java.net.Socket. host port)
                     (catch java.new.UnknownHostException _))
      socket-attempts (repeatedly make-socket)
      socket (first (drop-while nil? socket-attempts))]
  socket)

Upvotes: 0

Related Questions