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:
- Clojure Sequences - Working with lazy sequences
 - Macros - Extending the language with macros
 - Concurrency - Functional approaches to concurrency