Clojure tutorials for Beginners
1. Introduction to Clojure
Clojure is a dynamically typed, functional programming language that embraces immutability and encourages concise, expressive code.
2. Data Types
Clojure has several core data types, including numbers, strings, symbols, keywords, lists, vectors, maps, and sets.
(def num 42)
(def str "Hello, Clojure!")
(def sym 'foo)
(def keyword :bar)
(def lst '(1 2 3))
(def vec [4 5 6])
(def map {:name "Alice" :age 30})
(def set #{:apple :banana :cherry})
3. Basic Operations
Clojure provides standard arithmetic operations, string manipulation, and comparisons.
(+ 2 3) ; Addition
(- 7 4) ; Subtraction
(* 5 6) ; Multiplication
(/ 9 3) ; Division
(str "Hello" ", " "world!") ; String concatenation
(= 5 5) ; Equality
(< 10 15) ; Less than
(> 20 18) ; Greater than
4. Defining Functions
In Clojure, you define functions using the `defn` macro.
(defn add [a b]
(+ a b))
5. Anonymous Functions (Lambdas)
Anonymous functions can be created using the `fn` special form.
(def subtract (fn [a b]
(- a b)))
6. Higher-Order Functions
Clojure supports higher-order functions, which are functions that take other functions as arguments or return functions.
(defn apply-twice [f x]
(f (f x)))
7. Immutability
Clojure encourages immutability, meaning data structures are not modified in place. Instead, new modified versions are created.
(def original [1 2 3])
(def modified (conj original 4)) ; Adds 4 to the vector
8. Recursion
Clojure favors recursion over iteration for solving problems.
(defn factorial [n]
(if (<= n 1)
1
(* n (factorial (- n 1)))))
9. Destructuring
Destructuring allows you to extract values from complex data structures easily.
(def person {:name "Bob" :age 25})
(let [{name :name age :age} person]
(str name " is " age " years old."))
10. Pattern Matching
Clojure supports pattern matching through the `match` macro.
(defn describe-number [x]
(match x
0 "Zero"
1 "One"
:else "Other"))
11. Namespaces
Namespaces allow you to organize your code into logical units and avoid naming conflicts.
(ns my-app.core)
(defn my-function [x]
(* x x))
12. Maps and Keywords
Maps are key-value pairs, and keywords are used as identifiers.
(def person {:name "Alice" :age 30})
(:name person) ; Access value by keyword
(def book {:title "Clojure Programming" :author "John Doe"})
(:title book)
13. Vectors
Vectors are ordered collections that can hold various types of elements.
(def vector [1 "two" :three])
(nth vector 1) ; Access element at index 1
14. Sets
Sets are collections of unique elements.
(def fruits #{:apple :banana :cherry})
(conj fruits :orange) ; Add :orange to the set
15. Sequences and Laziness
Clojure supports lazy sequences, which are only computed as needed.
(def nums (range 10)) ; Lazily generates numbers from 0 to 9
(take 5 nums) ; Returns the first 5 numbers
16. Map, Filter, and Reduce
Higher-order functions like `map`, `filter`, and `reduce` are commonly used for data transformations.
(def numbers [1 2 3 4 5])
(map #(* % 2) numbers) ; Doubles each element
(filter even? numbers) ; Filters out odd numbers
(reduce + numbers) ; Calculates the sum
17. Threading Macros
Threading macros (`->` and `->>`) simplify code by threading values through multiple function calls.
(-> 5
(* 2)
(+ 3)) ; Equivalent to (+ (* 5 2) 3)
(->> [1 2 3]
(map #(* % 2))
(filter even?)) ; Equivalent to (filter even? (map #(* % 2) [1 2 3]))
18. Atom and Ref
Atoms and refs provide mutable references in a controlled, synchronized manner.
(def counter (atom 0))
(swap! counter inc) ; Atomically increments the counter
(def shared-data (ref {}))
(dosync (alter shared-data assoc :key "value")) ; Synchronized update of ref
19. Protocols and Records
Protocols define behavior, and records are used for efficient data storage.
(defprotocol Shape
(area [this]))
(defrecord Circle [radius]
Shape
(area [this]
(* Math/PI (:radius this) (:radius this))))
20. Transducers
Transducers are composable transformations that can be applied to sequences.
(def add-one (map inc))
(def double (map #(* % 2)))
(def composed (comp add-one double))
(->> [1 2 3]
composed) ; Yields [3 5 7]
21. Macros
Macros allow you to write code that generates code, enabling powerful abstractions.
(defmacro unless [expr body]
`(if (not ~expr)
~body))
(unless (= x 0)
(println "x is not zero")) ; Expands to (if (not (= x 0)) (println "x is not zero"))
22. Error Handling with `try`
The `try` special form is used for exception handling.
(defn safe-divide [a b]
(try (/ a b)
(catch ArithmeticException e
(println "Error: " (.getMessage e))
:error)))
23. Metadata
Clojure allows you to attach metadata to values, providing additional information.
(def my-var ^{:author "Alice"} 42)
(meta my-var) ; Returns the metadata
24. Namespaced Keywords
Namespaced keywords
are used to avoid naming conflicts between different libraries.
(def my-ns-keyword ::my-namespace/key)
25. Dynamic Vars
Dynamic vars are thread-bound, mutable variables with dynamic scope.
(def ^:dynamic *language* "Clojure")
(defn greet []
(println (str "Hello, " *language* "!")))
(binding [*language* "Python"]
(greet)) ; Outputs "Hello, Python!" temporarily
26. Java Interoperability
Clojure seamlessly integrates with Java code.
(def ArrayList (java.util.ArrayList.))
(.add ArrayList "item")
27. Lazy Sequences and Memoization
Lazy sequences can be memoized to improve performance.
(def fib-seq
(map first
(iterate
(fn [[a b]] [b (+ a b)])
[0 1])))
(def fib (take 10 fib-seq)) ; Calculates Fibonacci sequence lazily
28. Macros for DSLs
Macros can be used to create domain-specific languages (DSLs) for specific problem domains.
(defmacro sql
[query]
`(println "Executing SQL query:" ~query))
(sql "SELECT * FROM users WHERE age > 18")
29. Testing with `clojure.test`
Clojure provides a testing library for unit testing.
(ns my-app.core-test
(:require [clojure.test :refer :all]
[my-app.core :refer :all]))
(deftest test-add
(is (= 7 (add 3 4))))
(run-tests)
30. Interacting with the REPL
The REPL (Read-Eval-Print Loop) is a powerful tool for interactive development in Clojure.
(defn greet [name]
(str "Hello, " name "!"))
(greet "Alice") ; Evaluates to "Hello, Alice!"