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
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)))
letis 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)))))
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])
pairis interpreted as name of function
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.