params => positional-params*, or positional-params* & rest-param positional-param => binding-form rest-param => binding-form binding-form => name, or destructuring-form Defines a function. See https://clojure.org/reference/special_forms#fn for more information
;; simple anonymous function passed to (map ) user=> (map (fn [x] (* x x)) (range 1 10)) (1 4 9 16 25 36 49 64 81) ;; anonymous function with a name. not so anonymous now is it? ;; this is useful in stack traces (fn add [a b] (+ a b)) ;; anonymous function with two params, the second is destructured user=> (reduce (fn [m [k v]] (assoc m v k)) {} {:b 2 :a 1 :c 3}) {2 :b, 1 :a, 3 :c} ;; define and instantly call an anonymous function user=> ((fn [a b c] (+ a b c)) 2 4 6) 12 ;; define and instantly call an anonymous variadic function ;; "nums" is a list here user=> ((fn [& nums] (/ (apply + nums) (count nums))) 1 2 3 4) 5/2 ;; define and instantly call an anonymous mixed function ;; "nums" is a list, while "int" is a number user=> ((fn [int & nums] (+ int (/ (apply + nums) (count nums)))) 10 1 2 3 4) 25/2 ;; define and instantly call an anonymous overloaded function ;; even though it is quite pointless user=> ((fn ([a] (inc a)) ([a b] (+ a b))) 3) 4
;; the shortcut form for (fn ) is #( ) ;; where parameters are referred by their index with the prefix % ;; the equivalent of user=> ((fn [a b c] (+ a b c)) 2 4 6) 12 ;; is user=> (#(+ %1 %2 %3) 2 4 6) 12
;; shortcut form #() cannot be used for maps etc. user=> ((fn [] {:a 1})) {:a 1} user=> (#({:a 1})) ArityException Wrong number of args (0) passed to: PersistentArrayMap user=> (#([1])) ArityException Wrong number of args (0) passed to: PersistentVector ;; explanation for the first error: ;; #(f) is a shortcut for (fn [] (f)) ;; that means (#({:a 1})) is shortcut for ((fn [] ({:a 1}))) ;; which leads to the error above because you cannot apply a map to an empty ;; argument list. ;; i.e. you can only use #() shortcut if the fn body is a list. ;; As ((fn [] {:a 1})) has the same result ;; as ((fn [] (identity {:a 1}))), you can write: user=> (#(identity {:a 1})) {:a 1}
;;map and anonymous function ;;apply a function to a collection using an anonymous function (defn byten [nums] (map #(* 10 %) nums)) (byten [1 2 3 4 5]) ;;(10 20 30 40 50)
;; shortcut form #() expands to an args-list-count as per ;; the highest N in %N references within it, ;; irrespective of whether a lower %N is referenced or not: (macroexpand-1 '#(prn)) ;;=> (fn* [] (prn)) (macroexpand-1 '#(prn %)) ;;=> (fn* [p1__13122#] (prn p1__13122#)) (macroexpand-1 '#(prn %1)) ;;=> (fn* [p1__13127#] (prn p1__13127#)) (macroexpand-1 '#(prn %2)) ;;=> (fn* [p1__13133# p2__13132#] (prn p2__13132#)) ;; This will not work because the shortcut expands to a 0-arg fn: (let [a (atom :val0)] (add-watch a :key #(prn 'CHANGED)) (reset! a :val1)) ;; Execution error (ArityException) at user/eval13174 (form-init5982058823921663207.clj:3). ;; Wrong number of args (4) passed to: user/eval13174/fn--13175 ;; But this will work because simply referring to %4 expands it to a 4-arg fn: (let [a (atom :val0)] (add-watch a :key #(do %4 (prn 'CHANGED))) (reset! a :val1)) ;;CHANGED ;;=> :val1 ;; See the 4th bullet-point under "dispatch macro": ;; https://clojure.org/reference/reader#_dispatch
Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+)) with any doc-s...
The signature is wrong. It should be (quoting from clojure.org)
(fn name? [params* ] exprs*)
(fn name? ([params* ] exprs*)+)
@terjedahl name?
allows for self-recursion, as well as generating more human-friendly class names; it can also make the code clearer.
This leaves more questions. What is the performance cost? Why (fn name...) is repeated twice? What is a "binding-form"?
The syntax looks good compared to lambda function syntax in other programming languages.
fn
also supports the prepost map, the same as defn
boot.user=> (def adder (fn [x] {:post [(pos? %)]} (inc x))) #'boot.user/adder boot.user=> (adder -2) java.lang.AssertionError: Assert failed: (pos? %)