ClojureDocs

Nav

Namespaces

fn

clojure.core

Available since 1.0 (source)
  • (fn name? [params*] exprs*)
  • (fn name? ([params*] exprs*) +)
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
5 Examples
;; 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
See Also

Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+)) with any doc-s...

6 Notes
    By , created 11.0 years ago, updated 11.0 years ago

    The signature is wrong. It should be (quoting from clojure.org)

    (fn name? [params* ] exprs*)

    (fn name? ([params* ] exprs*)+)

    By , created 9.0 years ago

    What is the purpose of name? ?

    By , created 8.9 years ago

    @terjedahl name? allows for self-recursion, as well as generating more human-friendly class names; it can also make the code clearer.

    By , created 8.6 years ago

    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.

    By , created 8.5 years ago

    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? %)
    
    By , created 4.5 years ago, updated 4.5 years ago

    A function can be defined taking specified keyword arguments:

    (defn foo [req-1 req-2 & {:keys [key-1 key-2]}
       (list req-1 req-2 key-1 key-2))
    
    (foo a b)
    (foo a b :key-1 100)
    (foo a b :key-2 200)
    (foo a b :key-2 100 :key-1 200)