Search code examples
clojure

Clojure function/macro to apply functions until one returns something other than nil


Currently I have some code like this:

(defn compute-issue [some args] (or (age-issue some args) (name-issue some args)))

More issue types are coming. Is there something like this:

(defn compute-issue [some args] (first-not-nil [age-issue name-issue] some args))
; Where first-not-nil would be something like
(defn first-not-nil [fs & args]
  (if (empty? fs)
    nil
    (let [result (apply (first fs) args)]
      (if (nil? result)
        (recur (rest fs) args)
        result))))

I'm new to Clojure. Am I reinventing an existing function?


Solution

  • There is a similar function some-fn in clojure.core:

    Takes a set of predicates and returns a function f that returns the first logical true value returned by one of its composing predicates against any of its arguments, else it returns logical false. Note that f is short-circuiting in that it will stop execution on the first argument that triggers a logical true result against the original predicates.

    The key differences are some-fn returns another function for the actual function application, and that function will also discard false results, which it sounds like you may not want. This is another simple way to phrase it:

    (defn first-not-nil [fs & args]
      (first
       (for [f fs
             :let [r (apply f args)]
             :when (some? r)]
         r)))