Clojure: Functions
function expression: fn
fn
defines a function. It returns a expression that represents a function. (“fn” is similar to traditional lisp's “lambda”)
;; 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.
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”.
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.)
;; 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)