CodeToLive

Clojure Functions

Functions are the building blocks of Clojure programs. Clojure provides powerful tools for creating and composing functions in a functional programming style.

Defining Functions

Basic Function Definition


(defn greet
  "Returns a greeting string"
  [name]
  (str "Hello, " name "!"))

(greet "Alice") ; => "Hello, Alice!"
                

Multi-arity Functions


(defn greet
  "Returns a greeting string"
  ([] (greet "World"))
  ([name] (str "Hello, " name "!")))

(greet)       ; => "Hello, World!"
(greet "Bob") ; => "Hello, Bob!"
                

Variadic Functions


(defn sum
  "Sums all arguments"
  [& numbers]
  (apply + numbers))

(sum 1 2 3) ; => 6
                

Anonymous Functions

fn Form


(def increment (fn [x] (+ x 1)))
(increment 5) ; => 6
                

Short Syntax


(#(* % 2) 5)     ; => 10 (double)
(#(str %1 " and " %2) "salt" "pepper") ; => "salt and pepper"
                

Higher-Order Functions

map


(map inc [1 2 3]) ; => (2 3 4)
(map #(* % %) [1 2 3]) ; => (1 4 9)
                

filter


(filter even? [1 2 3 4]) ; => (2 4)
(filter #(> % 2) [1 2 3 4]) ; => (3 4)
                

reduce


(reduce + [1 2 3 4]) ; => 10
(reduce * 2 [1 2 3]) ; => 12 (with initial value 2)
                

complement


(filter (complement even?) [1 2 3 4]) ; => (1 3)
                

Function Composition

comp


(def inc-and-double (comp #(* % 2) inc))
(inc-and-double 5) ; => 12
                

partial


(def add5 (partial + 5))
(add5 10) ; => 15
                

juxt


((juxt + * min max) 2 3) ; => [5 6 2 3]
                

Recursion

Simple Recursion


(defn factorial
  [n]
  (if (<= n 1)
    1
    (* n (factorial (dec n)))))

(factorial 5) ; => 120
                

Tail Recursion with recur


(defn factorial
  [n]
  (loop [count n acc 1]
    (if (zero? count)
      acc
      (recur (dec count) (* acc count)))))

(factorial 5) ; => 120
                

Multimethods


(defmulti area :shape)

(defmethod area :circle
  [{:keys [r]}]
  (* Math/PI r r))

(defmethod area :rectangle
  [{:keys [w h]}]
  (* w h))

(area {:shape :circle :r 5})    ; => 78.539...
(area {:shape :rectangle :w 2 :h 3}) ; => 6
                

Protocols


(defprotocol Greeter
  (greet [this]))

(defrecord English []
  Greeter
  (greet [this] "Hello!"))

(defrecord Spanish []
  Greeter
  (greet [this] "¡Hola!"))

(greet (->English)) ; => "Hello!"
(greet (->Spanish)) ; => "¡Hola!"
                

Function Metadata


(defn ^{:doc "Adds two numbers" :added "1.0"} add
  [x y]
  (+ x y))

(meta #'add) ; => {:doc "Adds two numbers", :added "1.0", ...}
                

Pre/Post Conditions


(defn constrained-sqrt
  [x]
  {:pre [(pos? x)]
   :post [(> % 0)]}
  (Math/sqrt x))

(constrained-sqrt 25) ; => 5.0
(constrained-sqrt -25) ; => AssertionError
                

Memoization


(defn fib [n]
  (if (< n 2)
    n
    (+ (fib (dec n)) (fib (- n 2)))))

(def memo-fib (memoize fib))

(time (fib 35)) ; => "Elapsed time: 1000 ms"
(time (memo-fib 35)) ; First call: "Elapsed time: 1000 ms"
(time (memo-fib 35)) ; Subsequent calls: "Elapsed time: 0.1 ms"
                

Function Patterns

Function Factories


(defn make-adder
  [x]
  (fn [y] (+ x y)))

(def add5 (make-adder 5))
(add5 10) ; => 15
                

Closures


(defn make-counter
  []
  (let [count (atom 0)]
    (fn []
      (swap! count inc))))

(def c (make-counter))
(c) ; => 1
(c) ; => 2
                

Higher-order Helpers


(defn apply-twice
  [f x]
  (f (f x)))

(apply-twice #(* % 2) 5) ; => 20
                

Performance Considerations

  • Primitive type hints: Use ^long, ^double etc. for performance-critical numeric functions
  • Transducers: For efficient sequence processing (covered in Sequences section)
  • Inlining: Use ^:inline metadata for small functions

Next Steps

Continue learning with: