100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Clojure Syntax Basics

A tour of Clojure's core syntax: s-expressions, literal data types, the four collection types, and how to define values and functions.

FoundationsBeginner10 min readJul 10, 2026
Analogies

Clojure Syntax Basics

Clojure syntax is built entirely from s-expressions: nested lists surrounded by parentheses where the first element is evaluated as a function or macro and the remaining elements are its arguments. Unlike most mainstream languages, Clojure uses consistent prefix notation everywhere — (+ 1 2) rather than 1 + 2 — and every form, not just expressions in the traditional sense, evaluates to a value.

🏏

Cricket analogy: In Clojure, every form is an expression that returns a value, much like every ball bowled in a T20 match produces a definite outcome recorded on the scoreboard — there's no action that just happens and vanishes, because (+ 1 2) always evaluates to 3, not merely 'runs 3.'

Literals and Data Types

Clojure has literal syntax for numbers (integers, doubles, and ratios like 1/3), strings in double quotes, booleans true and false, and nil to represent an intentional absence of value. It also has two special reference types: symbols, which name and refer to bound values, and keywords like :active, which are self-evaluating constants commonly used as map keys or enumerated tags.

🏏

Cricket analogy: Clojure's keyword :not-out is like a fixed scoring code on a scorecard — unlike a batter's name, which refers to something else, a keyword like :not-out always evaluates to itself, the same way 'NO' on a scorecard is a fixed abbreviation, not a reference to another player.

Collections: Lists, Vectors, Maps, and Sets

Clojure provides four core collection literals: lists '(1 2 3), which are optimized for adding to the front and sequential traversal; vectors [1 2 3], which support fast indexed access and appending to the end; maps {:k1 v1 :k2 v2}, which associate keys with values; and sets #{1 2 3}, which store unique, unordered elements. Choosing the right collection type for the access pattern you need is a core Clojure skill.

🏏

Cricket analogy: A Clojure vector like [4 6 0 1] recording ball-by-ball outcomes preserves order and allows fast indexed access to, say, the 3rd ball of the over, the way a scorer instantly looks up 'what happened on ball 3' without scanning the whole over.

Defining Values and Functions

The def special form binds a name to a value at the top level, e.g. (def pi 3.14159). The defn macro combines def with fn to define a named function in one step: (defn square [x] (* x x)). For short, throwaway logic, Clojure also offers anonymous function syntax via fn or the compact #(...) reader macro, where % refers to the single argument.

🏏

Cricket analogy: Defining a function with defn is like the ICC formally codifying a new law in the Laws of Cricket, such as the 2017 update on bat-edge width limits — once (defn calculate-strike-rate [runs balls] (* 100 (/ runs balls))) is defined, that named operation can be reused identically in every future 'match' of your program.

clojure
;; Literals and basic values
(def pi 3.14159)
(def greeting "Hello, Clojure!")
(def status :active)

;; A vector, a map, and a set
(def scores [98 87 92 100])
(def player {:name "Ada" :level 12 :class :wizard})
(def unique-tags #{:beginner :clojure :functional})

;; Defining a named function
(defn celsius->fahrenheit [c]
  (+ 32 (* c (/ 9 5))))

;; An anonymous function used inline
(map #(* % %) [1 2 3 4])
;; => (1 4 9 16)

(println (celsius->fahrenheit 100))
;; => 212

In Clojure, nil and the boolean false are the only 'falsy' values in conditional contexts — every other value, including 0, empty strings, and empty collections, is treated as truthy. This trips up many newcomers coming from languages like Python or JavaScript where 0 and empty collections are falsy.

  • Every Clojure form is an expression that evaluates to a value; there are no bare statements.
  • Clojure uses prefix notation: the operator or function always comes first inside parentheses, e.g. (+ 1 2).
  • Core literal types include numbers, strings, keywords (:like-this), symbols, booleans, and nil.
  • Lists '(1 2 3) are optimized for sequential access; vectors [1 2 3] support fast indexed lookup.
  • Maps {:k v} associate keys with values; sets #{1 2 3} store unique, unordered elements.
  • def binds a name to a value; defn defines a named function.
  • Anonymous functions can be written with fn or the shorthand #(...) syntax for quick, inline use.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#ClojureStudyNotes#ClojureSyntaxBasics#Clojure#Syntax#Literals#Data#StudyNotes#SkillVeris#ExamPrep