top of page

Clojure tutorials for Beginners

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!"



0 views
bottom of page