Before we begin, you may want to install Clojure and Leiningen (which is a tool for managing projects in Clojure). This will let you run Clojure in the command line using a REPL (Read-Evaluate-Print-Loop).
The bread and butter of any programming language are variables and functions. Let’s define a variable!
(def our-string "Hello world!")
Easy peasy. That piece of code uses the
def macro to associate a string (
"Hello world!") to a symbol (
our-string). We could also have defined a number, such as
1.1, a character, such as
\Z, or something more complicated like a list or a regular expression (uuuugh).
Note that our code is inside parentheses, like a list, because everything in a Lisp is a list! (That will be very important when we start talking about macros.)
Now, let’s define a function!
(defn hello-world  (println our-string))
This is a bit more complex. Like
def, it uses a macro (
defn) to create a variable - although this time, that variable is a function. The empty vector (a vector is a type of list – think of it like an array) after
hello-world defines the arguments to that function – in this case, we don’t have any. The code after that is what the function does. It evaluates
our-string, which is equal to
"Hello world!", and prints it to the console. Let’s run it!
(hello-world) ; => Hello world! ; nil
You could also write this:
(def hello-world (fn  (println our-string)))
defn is just a shortcut to help keep your code concise.
(defn ...) and
(def ... (fn ...)) are the same in practice.
Well, that was nice, but it wasn’t really exciting. Let’s try a function with parameters. How about one that adds 3 numbers?
(defn add [x y z] (+ x y z)) (add 1 2 3) ; => 6
(+ x y z)? That looks funny. Well, Lisps are written using “prefix notation”, which means that the function always comes first. Since all mathematical operators in Lisp (
+ - * /) are just functions, they also come before their arguments (in this case,
x y z).
You’ll notice that our vector has some stuff in it now:
[x y z]! Whenever a function has parameters, you define them in that vector next to the function’s name.
A great feature about arguments in Clojure is destructuring. It allows you to ‘pull’ elements out of a list.
(defn add [[x y] z] (+ x y z)) (add [1 2] 3) ; => 6
The arguments to that function are a collection (
[x y]) and a number (
z). We can use destructuring to pull the first and second elements out of the list, and call them
Functions with any number of parameters
You can also define a function with an arbitrary number of arguments using
(defn demonstrate-rest [first & rest] (println first) (println rest)) (demonstrate-rest 1 "foo" ["bar" 22]) ; => 1 ; ("foo" ["bar" 22]) ; nil
As you can see, using
& separated our function’s arguments into one variable called
first and a list of variables called
rest. This means that our function could have any number of arguments!
You may have noticed some odd things. Whenever we use
println, it seems like
nil is showing up in our output. Furthermore, our
add function returns
6, but we never told it to return anything.
In Clojure, returns are ‘implicit’. If you’ve used Ruby, you’re probably familiar with this concept. Rather than telling our function to return something, it evaluates all the code inside its body, and returns the result. Our
add function, for example, evaluates
(+ x y z), and then returns that result.
The reason why our functions that use
nil is because
println evaluates to
nil is like
None – it represents nothing.)