Parens vs Brackets in Clojure

Summary: Clojure uses both parentheses and square brackets as part of its syntax. It might at first appear to be arbitrary, but it's actually systematic. What's more, it reveals one of the coolest things about Clojure: expressions define how they interpret their arguments.

The other day someone asked me a very good question about Clojure. She was learning the syntax and was wondering what the significance was between parentheses and square brackets. She knew that square brackets can also make a vector. What she really wanted to know what in the more syntactic elements, like the square brackets in a let or fn, why did you use parens sometimes and brackets other times?

The answer is simple: parens are for enclosing function calls or macro calls, while the square brackets inside are data for the macro to use. For instance, in the following let form, the parens define the lexical scope of the bindings while the bindings themselves are in square brackets.

(let [x 1
      y 2
      z 3]
  (* z (+ x y)))

here, parens mean "start a let expression"

binding form gets meaning from let

bindings in square brackets

parens because body of let is more calls

Notice the body (* z ...) is again in parens because it's function calls.

In the following defn, we have the parens defining the whole form while the brackets define the data the function definition needs, namely the argument names.

(defn fib [x]
  (cond
    (= 0 x) 1
    (= 1 x) 1
    :else   (+ (fib (- x 1)) (fib (- x 2)))))

start a "defn" expression

agument list gets meaning from defn

body is more parens

Finally, we can see that brackets also mean "create a vector" in this expression:

(defn pair
  "Create a pair from the two arguments."
  [a b]
  [a b])

symbol pair is interpreted as name of function

a string after the name is interpreted as the docstring

these are the arguments

everything else is the body; make and return a vector

The first element of an expression is used to determine how to interpret the rest. Clojure is basically interpreters (and compilers) all the way down. It's one of the coolest things about Lisps. From the get-go, they're defined in terms of themselves, recursively. If you'd like to learn Clojure, join the PurelyFunctional.tv Online Mentoring program. It's an exploration in interactive instruction. When you join, you set the topics, you get help where you need it, to become a Clojure professional.