CodeToLive

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: