Clojure: Functions

By Xah Lee. Date: . Last updated: .

function expression: 「fn」

fn defines a function. It returns a expression that represents a function. (“fn” is similar to traditional lisp's “lambda”)

clojure.core/fn

;; this is a function. aka lambda, anonymous function
(fn [x y] (+ x y))
;; define a function and apply it to 3 4
((fn [x y] (+ x y)) 3 4) ; 7
;; anonymous function can be given a name, if you want to call it in body for recursion
(
(fn hh [n]
    (if (< n 5)
        (hh (inc n))
      6
      ))
3
) ; ⇒ 6

;; this is shown as example. Better is to replace hh inside by “recur”

you can use def and fn together to define a named function.

(def yy
     (fn [x y] (+ x y)))

(yy 3 4) ; 7

Defining a function and assign it to a variable is often used. So, there's a syntax shortcut “defn”.

(defn name …)

is equivalent to

(def name (fn …))

define and name function: 「defn」

;; define a function
(defn ff
  "Add 2 numbers"
  [x y]
  (+ x y))

(ff 3 4) ; 7

Note: doc string comes after the function name, BEFORE the parameters.

Note: square brackets [] is used for parameters.

clojure.core/defn

Unspecified Number of Parameters

To define a function with unspecified number of parameters, add & rest to the end of parameter vector. This is usually called “rest parameters”. clojure.core/&

In the function body, the rest arg rest is a list.

;; function with 0 or more parameters
(defn cc [& xx] (count xx))

(cc) ; ⇒ 0

(cc 4 5 6) ; ⇒ 3

(count returns the number of items in the collection.) clojure.core/count

;; function with 1 or more parameters
(defn dd
  [x & xx]
  xx)

(dd) ; ArityException Wrong number of args (0) passed to: core/dd  clojure.lang.AFn.throwArity (AFn.java:429)

(dd 4) ; nil. When arg not received, it's nil

(dd 4 5) ; (5)

Polymorphism

A function can be defined with different behavior depending on number of arguments or argument's type. (this is called “polymorphism”)

Normally, function has this form:

(defn name […] body)

To define a function that depends on number of args, use this form:

(defn name ([…] body1) ([…] body2) …)

;; function with different behavior depending on arity
(defn gg
  ([] 0) ; no argument, return 0
  ([x] x) ; 1 arg, return itself
  ([a b] (+ a b) ; 2 args, add them
     ))

(println (gg))   ; 0
(println (gg 3))   ; 3
(println (gg 3 4))   ; 7

syntax shortcut for fn

(fn [x] (body))

is equivalent to

#(body)

and in body, % stand for 1st argument, %1 is the 1st argument. %2 is 2nd argument, etc.

;; syntax shortcut for function “fn”
#(+ % %)

;; same as
(fn [x] (+ x x))

the % is the argument.

;; syntax shortcut for function “fn”
#(+ %1 %2)

;; same as
(fn [x y] (+ x y))

%1 is the 1st argument. %2 is 2nd argument.

pre-condition and post-condition

function can have pre-condition (sometimes called “guards”). If the condition isn't met, the function won't run.

;; function can have pre-condition

;; make sure the arg is greater than 1
(defn ff [xx] {:pre [(> xx 1)]} xx)

(ff 2) ; ⇒ 2

(ff 1) ; AssertionError Assert failed: (> xx 1)  user/ff (form-init5996506143908541499.clj:1)

clojure.core/defn

Here's a example of post-condition.

;; function can have post-condition

;; make sure the result is less than 10
(defn gg [yy] {:post [(< % 10)]} (Math/pow yy 2))

(gg 2) ; ⇒ 4

(gg 5) ; AssertionError Assert failed: (< % 10)  user/gg (form-init5996506143908541499.clj:1)

Function Binding Forms

when defining a function, the parameter spec […] can be a nested structure, used to do “Destructure Binding”.

See: Clojure: Binding Forms, Destructuring.

Function Chaining

Clojure: Function Chaining

partial function generator (currying)

see Clojure: Partial Function (Currying)