Introduction to Clojure
Clojure is a modern, functional programming language that runs on the Java Virtual Machine (JVM). It combines the interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming.
Why Clojure?
- Functional Programming: Clojure is a functional-first language with immutable data structures
- Lisp Dialect: Simple, consistent syntax with powerful macro system
- JVM Integration: Full access to Java libraries and ecosystem
- Concurrency: Built-in support for safe, easy concurrent programming
- Dynamic: Interactive development with REPL-driven workflow
Installing Clojure
There are several ways to install Clojure:
1. Using Leiningen (Recommended)
# On macOS with Homebrew
brew install leiningen
# On Linux (Debian/Ubuntu)
sudo apt-get install leiningen
# On Windows (using Chocolatey)
choco install leiningen
2. Using Clojure CLI tools
# On macOS with Homebrew
brew install clojure/tools/clojure
# On Linux (using install script)
curl -O https://download.clojure.org/install/linux-install-1.10.3.1029.sh
chmod +x linux-install-1.10.3.1029.sh
sudo ./linux-install-1.10.3.1029.sh
Running Clojure
Start a REPL (Read-Eval-Print Loop) to interact with Clojure:
With Leiningen
lein repl
With Clojure CLI
clj
Basic Syntax
Clojure is a Lisp dialect, so everything is expressed in parentheses:
; This is a comment
; Simple expressions
(+ 1 2 3) ; => 6
(* 2 3) ; => 6
(/ 10 2) ; => 5
; Function calls look the same
(str "Hello" " " "World") ; => "Hello World"
Data Types
Clojure has several built-in data types:
; Numbers
42 ; Integer
3.14 ; Double
1/3 ; Ratio
; Strings
"Hello World"
; Characters
\a \b \c
; Booleans
true false
; Keywords (like Ruby symbols or Java enums)
:name :age :price
; Nil (null/none value)
nil
Defining Variables
Use def
to create global bindings:
(def x 10)
(def name "Alice")
(def pi 3.14159)
(println x) ; => 10
(println name) ; => "Alice"
Defining Functions
Create functions with defn
:
; Simple function
(defn greet [name]
(str "Hello, " name "!"))
(greet "Alice") ; => "Hello, Alice!"
; Multi-arity function
(defn greet
([] (greet "World"))
([name] (str "Hello, " name "!")))
(greet) ; => "Hello, World!"
(greet "Bob") ; => "Hello, Bob!"
; Function with docstring
(defn square
"Returns the square of x"
[x]
(* x x))
(square 5) ; => 25
Data Structures
Clojure has several immutable, persistent data structures:
Lists
'(1 2 3 4) ; List literal
(list 1 2 3 4) ; Same as above
; Lists are evaluated as function calls
(+ 1 2 3) ; => 6
Vectors
[1 2 3 4] ; Vector literal
(vector 1 2 3 4); Same as above
; Access by index
(def v [10 20 30 40])
(get v 1) ; => 20
(v 1) ; => 20 (same as above)
Maps
{:name "Alice" :age 30} ; Map literal
(hash-map :name "Alice" :age 30) ; Same as above
; Access values
(def person {:name "Bob" :age 25})
(get person :name) ; => "Bob"
(person :name) ; => "Bob" (same as above)
(:name person) ; => "Bob" (keyword as function)
Sets
#{1 2 3} ; Set literal
(hash-set 1 2 3); Same as above
; Check membership
(def numbers #{1 2 3 4})
(contains? numbers 2) ; => true
(contains? numbers 5) ; => false
Control Flow
Clojure provides several control flow constructs:
if
(if (> 3 2)
"3 is greater than 2"
"3 is not greater than 2")
; => "3 is greater than 2"
when
(when (> 3 2)
(println "It's true!")
"This is returned")
; Prints "It's true!" and returns "This is returned"
cond
(defn grade [score]
(cond
(>= score 90) "A"
(>= score 80) "B"
(>= score 70) "C"
(>= score 60) "D"
:else "F"))
(grade 85) ; => "B"
case
(defn day-name [n]
(case n
1 "Monday"
2 "Tuesday"
3 "Wednesday"
4 "Thursday"
5 "Friday"
6 "Saturday"
7 "Sunday"
"Invalid day"))
(day-name 3) ; => "Wednesday"
Looping and Recursion
Clojure provides several ways to loop:
loop/recur
(loop [i 0]
(when (< i 5)
(println i)
(recur (inc i))))
; Prints 0 through 4
doseq
(doseq [n (range 5)]
(println n))
; Prints 0 through 4
dotimes
(dotimes [i 5]
(println i))
; Prints 0 through 4
Recursive function
(defn factorial [n]
(if (<= n 1)
1
(* n (factorial (dec n)))))
(factorial 5) ; => 120
Working with Java
Clojure has excellent Java interoperability:
; Create Java objects
(def date (java.util.Date.))
; Call methods
(.getTime date) ; => milliseconds since epoch
; Static methods
(System/currentTimeMillis)
; Import classes
(import 'java.util.ArrayList)
; Use Java collections
(def alist (ArrayList. [1 2 3]))
(.add alist 4)
alist ; => [1 2 3 4]
Next Steps
Now that you've learned the basics, you can explore:
- Clojure Data Structures - More about collections
- Functions - Higher-order functions and functional patterns
- Sequences - Working with lazy sequences