Search code examples
functional-programmingclojure

if-else branching in clojure


I'm teaching myself Clojure.

In a non-FP language, I could easily enough write nested if's, and if I didn't specifically put an else, then control would just flow out of the if block. For example:

Thing myfunc()
{
  if(cond1)
  {
    if(cond2)
      return something;
  }
  return somethingelse;
}

However, in Clojure, there's no return statement (that I know of), so if I write:

(defn myfunc []
  (if (cond1)
      (if (cond2) something))
  somethingelse)

then there's no "return" on "something". It seems to just kind of say, ok, here we have a value, now let's keep on executing. The obvious solution would be to combine the conditions, i.e.:

(if (and (cond1) (cond2))
    something
    somethingelse)

but this gets unwieldy/ugly for large conditions. Also, it would take additional finagling to add a statement to the "else" part of cond1. Is there any kind of elegant solution to this?


Solution

  • This is the subtle difference between imperative and functional approach. With imperative, you can place return in any place of the function, while with functional the best way is to have clear and explicit exeecution paths. Some people (me including) prefer the latter approach in imperative programming as well, recognizing it as more obvious and manageable and less error-prone.

    To make this function explicit:

    Thing myfunc() {
      if(cond1) {
        if(cond2)
          return something;
      }
    
      return somethingelse;
    }
    

    You can refactor it to:

    Thing myfunc() {
      if(cond1 && cond2) {
          return something;
      } else {
        return somethingelse;
      }
    }
    

    In Clojure, its equivalent is:

    (defn myfunc []
      (if (and cond1 cond2) 
          something
          somethingelse))
    

    If you need an "else", your Java version could become:

    Thing myfunc() {
      if(cond1) {
        if(cond2) {
          return something;
        } else {
          return newelse;
        }
      } else {
        return somethingelse;
      }
    }
    

    ... and its Clojure equivalent:

    (defn myfunc []
      (if cond1
          (if cond2 something newelse)
          somethingelse))