bindings => binding-form test When test is true, evaluates body with binding-form bound to the value of test
;; 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
;; 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
bindings => binding-form test If test is true, evaluates then with binding-form bound to the valu...
Evaluates test. If logical false, evaluates body in an implicit do.
bindings => x xs Roughly the same as (when (seq xs) (let [x (first xs)] body)) but xs is evaluate...
bindings => binding-form test When test is not nil, evaluates body with binding-form bound to th...
binding => binding-form init-expr binding-form => name, or destructuring-form destructuring-form...
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...).
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.