if-let

clojure.core

  • (if-let bindings then)
  • (if-let bindings then else & oldform)
bindings => binding-form test

If test is true, evaluates then with binding-form bound to the value of
test, if not, yields else

5 Examples top

  • user=> (defn sum-even-numbers [nums]
             (if-let [nums (seq (filter even? nums))]
               (reduce + nums)
               "No even numbers found."))
    #'user/sum-even-numbers
    
    user=> (sum-even-numbers [1 3 5 7 9])
    "No even numbers found."
    
    user=> (sum-even-numbers [1 3 5 7 9 10 12])
    22
    
  • user=> (if-let [x false y true]
             "then"
             "else")
    java.lang.IllegalArgumentException: if-let requires exactly 2 forms in binding vector (NO_SOURCE_FILE:1)
    
    user=> (defn if-let-demo [arg]
             (if-let [x arg]
               "then"
               "else"))
    
    user=> (if-let-demo 1) ; anything except nil/false
    "then"
    user=> (if-let-demo nil)
    "else"
    user=> (if-let-demo false)
    "else"
    
  • ; This macro is nice when you need to calculate something big. And you need 
    ; to use the result but only when it's true:
    
    (if-let [life (meaning-of-life 12)]
       life
       (if-let [origin (origin-of-life 1)]
          origin
          (if-let [shot (who-shot-jr 5)]
             block-sol
    	 42)))
    
    ; As you can see in the above example it will return the answer 
    ; to the question only if the answer is not nil. If the answer
    ; is nil it will move to the next question. Until finally it
    ; gives up and returns 42.
  • ;; See examples for "if" explaining Clojure's idea of logical true
    ;; and logical false.
  • ;;; with distructuring binding
    
    ;; successful case
    (if-let [[w n] (re-find #"a(\d+)x" "aaa123xxx")]
      [w n]
      :not-found)  ;=> ["a123x" "123"]
    
    ;; unsuccessful case
    (if-let [[w n] (re-find #"a(\d+)x" "bbb123yyy")]
      [w n]
      :not-found) ;=> :not-found
    
    ;; same as above
    (if-let [[w n] nil]
      [w n]
      :not-found) ;=> :not-found
    
    ;; on Map
    (if-let [{:keys [a b]} nil]
      [a b]
      :not-found) ;=> :not-found
    
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/core.clj:1666 top

(defmacro if-let
  "bindings => binding-form test

  If test is true, evaluates then with binding-form bound to the value of 
  test, if not, yields else"
  {:added "1.0"}
  ([bindings then]
   `(if-let ~bindings ~then nil))
  ([bindings then else & oldform]
   (assert-args if-let
     (and (vector? bindings) (nil? oldform)) "a vector for its binding"
     (= 2 (count bindings)) "exactly 2 forms in binding vector")
   (let [form (bindings 0) tst (bindings 1)]
     `(let [temp# ~tst]
        (if temp#
          (let [~form temp#]
            ~then)
          ~else)))))
Vars in clojure.core/if-let:
Used in 0 other vars

Comments top

1 comment(s) for if-let.

I wonder what motivates the restriction of only one binding, e.g. many Schemes implement an and-let* form which allows multiple bindings, evaluating them in order and breaking out on the first binding that evaluates to false. Can somebody shed some light on this?

Log in to add a comment.