✓ Functions

In this section, we will have an indepth discussion of functional programming.

Declaring Functions revisited

Function as value

(def add (fn [x y z] (+ x y z)))
#'user/add
(add 1 2 3)
6

Declaring function

(defn add [x y z]
    (+ x y z))
#'user/add
(add 1 2 3)
6

Anonymous function

(def add #(+ %1 %2 %3))
#'user/add
(add 1 2 3)
6

Variadic functions

Destructuring variadic parameters

(defn add-many [x y z & rest]
    (println "adding" x y z "and also" rest))
#'user/add-many
(add-many 1 2 3)
adding 1 2 3 and also nil
nil
(add-many 1 2 3 4 5 6 7)
adding 1 2 3 and also (4 5 6 7)
nil

Destructuring hash-map parameters

(defn add-numbers [{:keys [x y z more]}]
    (println "adding" x y z "and also" more))
#'user/add-numbers
(add-numbers {:x 1
              :y 2
              :z 3
              :more [4 5 6]})
adding 1 2 3 and also [4 5 6]
nil

Partial functions

Definition of partial function

Suppose we have a function \(f(x, y, z, \dots)\) with parameters \(x, y, z, \dots\). A partial function of \(f\) is a function defined by fixing certain parameters of \(f\).

\[ p(y, z, \dots) = f(\mathrm{value}, y, z, \dots) \]

Create partial functions

(def p (partial add-many 100))
#'user/p
(p 1 2 3 4 5)
adding 100 1 2 and also (3 4 5)
nil

Apply functions

Function application from a data perspective

Consider a function application below.

(add-many 1 2 3 4 5)

It can be seen as two pieces of data:

  1. the function expression: in this case add-many

  2. a collection of argument expressions: in this case 1, 2, 3, 4, 5

Clojure provides a function apply that can perform the function invocation when provided the function and argument list.

Apply

(apply <function> <arguments>)
(apply <function> <first-arg> <arguments...>)
(apply <function> <first-arg> <second-arg> <arguments...>)
(apply add-many [1, 2, 3, 4, 5])
adding 1 2 3 and also (4 5)
nil
(apply add-many 100 [1 2 3 4 5])
adding 100 1 2 and also (3 4 5)
nil

Defining partial functions using apply

(defn p [y z & more]
    (let [arguments (concat [y z] more)]
        (apply add-many 100 arguments)))
#'user/p
(p 1 2 3 4 5)
adding 100 1 2 and also (3 4 5)
nil

Summary

Three ways of function abstraction:

  1. (fn [...] ...)

  2. (defn f [...] ...)

  3. #(...)

Functions can have arbitary parameters

  1. Destructuring the arguments [ ... & <rest-args> ]

  2. Rest of the arguments are in a list.

Partial functions

  1. (partial f ...)

  2. Define a new function with (apply ...)