ClojureDocs

Nav

Namespaces

when-let

clojure.core

Available since 1.0 (source)
  • (when-let bindings & body)
bindings => binding-form test
 When test is true, evaluates body with binding-form bound to the value of test
8 Examples
;; Very useful when working with sequences. Capturing the return value 
;; of `seq` brings a performance gain in subsequent `first`/`rest`/`next`
;; calls. Also the block is guarded by `nil` punning.

(defn drop-one
  [coll]
  (when-let [s (seq coll)]
    (rest s)))

user=> (drop-one [1 2 3])
(2 3)
user=> (drop-one [])
nil
;; See examples for "if" explaining Clojure's idea of logical true
;; and logical false.
;; Works well with collections

(def x {:whatever 1})

(when-let [value (:whatever x)]
  (println "x+1 = " (inc value)))

;; Prints: "x+1 = 2"
;; when-let multiple bindings version

(defmacro when-let*
  ([bindings & body]
   (if (seq bindings)
     `(when-let [~(first bindings) ~(second bindings)]
        (when-let* ~(drop 2 bindings) ~@body))
     `(do ~@body))))

(when-let* [a 1 
            b 2 
            c (+ a b)]
           (println "yeah!")
           c)
;;=>yeah!
;;=>3

(when-let* [a 1 
            b nil 
            c 3]
            (println "damn! b is nil")
            a)
;;=>nil
;; test is evaluated before values are bound to binding, so destructuring works
(when-let [[a] nil] [a])
=> nil
(when-let [[a] [:a]] [a])
=> [:a]
(when-let [[a] []] [a])
=> [nil]
;; when-let multiple bindings version
;; all bindings are evaluated before checking for falsyness

(defmacro when-let*
          [bindings & body]
          `(let ~bindings
                (if (and ~@(take-nth 2 bindings))
                  (do ~@body)
                  )))

(when-let* [a 1 
            b 2 
            c (+ a b)]
           (println "yeah!")
           c)
;;yeah!
;;=> 3

(when-let* [a 1 
            b nil 
            c 3]
            (println "damn! b is nil")
            a)
;;=> nil
(require '[reagent.core :as r])

(def float-parsable? (comp not js/isNaN js/parseFloat))
(def find-parsable-or-nil 
  (comp first 
        (partial re-find 
                 #"(\-?\d+\.)?\d+([eE][-+]?\d+)?")))

(defn number-input
 "HTML input element for number only input"
 [value]
 [:input
  {:value @value
   :type "text"
   :on-change (comp
               #(when-let [new-value %]
                 (reset! value new-value))
               (fn [value]
                (cond
                 (empty? value) ""
                 (float-parsable? value) value
                 :otherwise (find-parsable-or-nil value)))
               (fn [target]
                (.-value target))
               (fn [event]
                (.-target event)))}])

(def value (r/atom ""))

(defn demo []
 [:div
  ; Displays NaN when value is "", displays a number otherwise.
  (-> @value js/parseFloat str) [:br]
  [number-input value]])
;; when-let with boolean values and nil

(when-let [f true] 
  (println "Hello world!!!"))

;; prints Hello world!!!

;;=>Hello world!!!
;;=>nil

(when-let [f false] 
  (println "Hi!!!"))

;; prints nothing

;;=>nil

(when-let [f nil] 
  (println "Wassup!!!"))

;; prints nothing

;;=>nil
See Also

bindings => binding-form test If test is true, evaluates then with binding-form bound to the valu...

Added by 0x89

Evaluates test. If logical true, evaluates body in an implicit do.

Added by srid

Evaluates test. If logical false, evaluates body in an implicit do.

Added by mmwaikar

Evaluates test.

Added by jafingerhut

bindings => x xs Roughly the same as (when (seq xs) (let [x (first xs)] body)) but xs is evaluate...

Added by ryo

bindings => binding-form test When test is not nil, evaluates body with binding-form bound to th...

Added by brunchboy

binding => binding-form init-expr binding-form => name, or destructuring-form destructuring-form...

Added by MicahElliott
4 Notes
    By , created 14.1 years ago

    The difference between when-let and if-let is that when-let doesn't have an else clause and and also accepts multiple forms so you don't need to use a (do...).

    By , created 11.1 years ago, updated 11.1 years ago

    The word "bindings" seems not to be correct here. In fact when-let only accepts one binding and not multiple ones. So "bindings" might be confusing, at least it was for me.

    By , created 10.7 years ago

    Agreed. It ought to be "binding" for clarity.

    By , created 8.1 years ago
    (when-let [name test]
      (do-something-with-name))
    

    In the example above, test does not have to be a predicate. test can be any value which is like (seq coll) or 3, [1 2], or so.

    If test is neither false nor nil, test is bound to name.