Explore essential Clojure syntax with this comprehensive guide, tailored for Java professionals transitioning to functional programming.
Welcome to the Clojure Syntax Quick Reference, a comprehensive guide designed specifically for Java professionals venturing into the world of functional programming with Clojure. This guide serves as a cheat sheet, covering essential Clojure syntax, including literals, special forms, core functions, and macros. As you transition from Java’s object-oriented paradigm to Clojure’s functional approach, this reference will help you grasp the nuances of Clojure’s syntax and idioms.
Clojure is a dynamic, functional programming language that runs on the Java Virtual Machine (JVM). It emphasizes immutability, first-class functions, and a minimalist syntax. Unlike Java, Clojure’s syntax is concise and expressive, allowing developers to write powerful code with fewer lines.
Literals in Clojure represent fixed values in the code. They include numbers, strings, characters, keywords, symbols, lists, vectors, maps, and sets.
Clojure supports various numeric types, including integers, floating-point numbers, ratios, and big integers.
42 ; Integer
3.14 ; Floating-point number
22/7 ; Ratio
2N ; Big integer
Strings in Clojure are sequences of characters enclosed in double quotes.
"Hello, Clojure!" ; String literal
Characters are prefixed with a backslash.
\a ; Character 'a'
\n ; Newline character
Keywords are identifiers that begin with a colon and are often used as keys in maps.
:keyword ; Keyword
Symbols are used to refer to variables and functions.
foo ; Symbol
Lists are ordered collections of elements, typically used to represent code.
'(1 2 3) ; List
Vectors are indexed collections, similar to arrays in Java.
[1 2 3] ; Vector
Maps are collections of key-value pairs.
{:name "Alice" :age 30} ; Map
Sets are collections of unique elements.
#{1 2 3} ; Set
Special forms are fundamental constructs in Clojure that provide the building blocks for more complex expressions. They include def
, if
, do
, let
, fn
, quote
, var
, loop
, recur
, throw
, try
, catch
, and finally
.
def
Defines a new variable or function.
(def x 10) ; Define a variable x with value 10
if
Conditional expression that evaluates one of two branches.
(if (> 10 5)
"Greater"
"Lesser") ; Evaluates to "Greater"
do
Groups multiple expressions, returning the value of the last expression.
(do
(println "Hello")
(+ 1 2)) ; Returns 3
let
Binds variables to values within a local scope.
(let [x 10
y 20]
(+ x y)) ; Returns 30
fn
Defines an anonymous function.
(fn [x] (* x x)) ; Function that squares its argument
quote
Prevents evaluation of an expression.
(quote (1 2 3)) ; Returns the list (1 2 3)
var
Refers to a variable in the current namespace.
(var x) ; Refers to the variable x
loop
and recur
Used for recursion with tail-call optimization.
(loop [i 0]
(when (< i 10)
(println i)
(recur (inc i)))) ; Prints numbers 0 to 9
throw
, try
, catch
, and finally
Used for exception handling.
(try
(/ 1 0)
(catch ArithmeticException e
(println "Cannot divide by zero"))
(finally
(println "Cleanup"))) ; Prints error message and "Cleanup"
Clojure provides a rich set of core functions for manipulating data structures, performing arithmetic operations, and more. Here are some commonly used functions:
(+ 1 2 3) ; Addition, returns 6
(- 10 5) ; Subtraction, returns 5
(* 2 3) ; Multiplication, returns 6
(/ 10 2) ; Division, returns 5
(conj [1 2] 3) ; Adds an element to a collection, returns [1 2 3]
(first [1 2 3]) ; Returns the first element, 1
(rest [1 2 3]) ; Returns the rest of the elements, (2 3)
(map inc [1 2 3]) ; Applies a function to each element, returns (2 3 4)
(filter even? [1 2 3 4]) ; Filters elements, returns (2 4)
(reduce + [1 2 3 4]) ; Reduces a collection, returns 10
(str "Hello, " "World!") ; Concatenates strings, returns "Hello, World!"
(clojure.string/upper-case "hello") ; Converts to uppercase, returns "HELLO"
(clojure.string/split "a,b,c" #",") ; Splits a string, returns ["a" "b" "c"]
(seq [1 2 3]) ; Converts a collection to a sequence, returns (1 2 3)
(cons 0 [1 2 3]) ; Adds an element to the front, returns (0 1 2 3)
(interleave [1 2] [3 4]) ; Interleaves two sequences, returns (1 3 2 4)
Macros in Clojure allow you to extend the language by defining new syntactic constructs. They are a powerful feature that enables metaprogramming.
defmacro
Defines a macro.
(defmacro unless [condition & body]
`(if (not ~condition)
(do ~@body))) ; Macro that acts like an inverted if
->
and ->>
Threading macros for chaining expressions.
(-> 5
(+ 3)
(* 2)) ; Threads the value through, returns 16
(->> [1 2 3]
(map inc)
(filter even?)) ; Threads the collection through, returns (2 4)
letfn
Defines local functions.
(letfn [(square [x] (* x x))
(cube [x] (* x x x))]
(println (square 3))
(println (cube 3))) ; Prints 9 and 27
map
, filter
, and reduce
to operate on collections.let
, fn
, and other forms.criterium
for benchmarking and optimizing performance-critical code.reduce
over Recursion: Use reduce
for accumulation tasks to avoid stack overflow errors.This Clojure Syntax Quick Reference provides a comprehensive overview of the essential syntax and constructs needed to write effective Clojure code. As a Java professional, embracing Clojure’s functional paradigm will open new possibilities for building robust, scalable applications. By mastering these syntax elements and best practices, you’ll be well-equipped to leverage Clojure’s power and expressiveness in your projects.