Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched.
;; a function that expects a non-nil value (defn say-hello [name] (str "Hello " name)) ;;=> #'user/say-hello ;; fnil lets you create another function with a default ;; arg in case it is passed a nil (def say-hello-with-defaults (fnil say-hello "World")) ;;=> #'user/say-hello-with-defaults ;; the happy path works as you would expect (say-hello-with-defaults "Sir") ;;=> "Hello Sir" ;; but in the case that the function is passed a nil it will use the ;; default supplied to fnil (say-hello-with-defaults nil) ;;=> "Hello World" ;; this works with different arities too (defn say-hello [first other] (str "Hello " first " and " other)) ;;=> #'user/say-hello ;; lets create it with defaults (def say-hello-with-defaults (fnil say-hello "World" "People")) ;;=> #'user/say-hello-with-defaults ;; call the function with all nil args - notice it uses the defaults ;; supplied to fnil (say-hello-with-defaults nil nil) ;;=> "Hello World and People" ;; any of the args can be nil - the function will supply ;; the default supplied with fnil (say-hello-with-defaults "Sir" nil) ;;=> "Hello Sir and People" ;; and again - notice that "World" is the default here (say-hello-with-defaults nil "Ma'am") ;;=> "Hello World and Ma'am" ;; or pass all args (say-hello-with-defaults "Sir" "Ma'am") ;;=> "Hello Sir and Ma'am"
;; Treat nil as 0 for the purposes of incrementing ((fnil inc 0) nil) ;;=> 1 ;; While the following would not work: (inc nil) ;;=> NullPointerException clojure.lang.Numbers.ops (Numbers.java:961) ;; fnil is very useful for specifying default values when updating maps ;; For a map containing counters of keys: (update-in {:a 1} [:a] inc) ;;=> {:a 2} ;; Oops, our map does not have a key :b and update-in passes nil to inc (update-in {:a 1} [:b] inc) ;;=> NullPointerException clojure.lang.Numbers.ops (Numbers.java:961) ;; But if we use fnil it works: (update-in {:a 1} [:b] (fnil inc 0)) ;;=> {:b 1, :a 1} ;; Another example is when map values are collections and we don't want ;; default behavior of conj with nil that produces a list (conj nil 1) ;;=> (1) ;; I.e. (update-in {} [:a] conj 1) ;;=> {:a (1)} ;; But say we want map values to be vectors instead: (update-in {} [:a] (fnil conj []) 1) ;;=> {:a [1]}
;;; Note that `fnil` still requires the appropriate number of arguments for an ;;; arity (i.e. no "implicit" default) (def tempids {-1 1 -2 2 -3 3}) (def id (fnil get nil -1)) ;; You may expect `fnil` to implicitly add -1 as the last argument, but that's ;; not true. (id tempids) ;;=> ArityException: Wrong number of args (1) passed to: clojure.core/fnil/fn--... ;; But it will here, since the argument is there (as `nil`). (id tempids nil) ;;=> 1 ;; Of course, you can supply it explicitly. (id tempids -1) ;;=> 1
Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variabl...
Takes a set of functions and returns a fn that is the composition of those fns. The returned fn t...
Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn...
Evaluates exprs one at a time, from left to right. If a form returns a logical true value, or retu...
Takes a set of predicates and returns a function f that returns the first logical true value retur...
fnil