Getting started with Clojure

Marco Nicolodi
Qualyteam Engineering
10 min readMay 20, 2019

Functional programming is all the hype now, getting out of academic land and powering big companies that addresses complex problems. You can do functional with object oriented languages, like C#, or even with multi paradigm languages like Javascript, but there are some languages that address the functional paradigm by design, like Clojure.

For shocking purposes, I’m going to show a piece of Clojure code. You are probably going to think it’s esoteric and hard to reason about, but I promise you will undertand its awesomeness by the end of this article:

Typical Clojure code that is awesome

Still here? Guess you challenged yourself to get out of your confort zone! This article is going to show you the minimal theory and language constructs that you need to know to start writing simple Clojure programs, and how to (not even) setup your environement to start playing. Finally, I’m going to share some resources if you feel like deep diving.

Introduction

Clojure is a LISP Dialect, functional first programming language that runs on the JVM.

What does that mean? By LISP (List Processing) dialect, you just need to know that a clojure program is represented by lists. Yes, everything is a List, even a function call. You can see that:

Since everything is a list, there’s almost no syntax to learn.

Since a List in Clojure is surrounded by parenthesis and a Clojure program is mostly a bunch of lists, you are going to see lots of parenthesis. But you get used to it.

This differs on other languages as their programms are usually represented by streams of characters that follows certain syntax. In Clojure, there’s almost no syntax besides the data structures that represents our program. Therefore, there’s not much to learn, making it very simple and syntax pollution free.

By a functional language, we can say that it has first class functions, meaning that a function can receive a function as parameter, return another function, and be stored as a value.

Clojure also praises immutability, pureness and side effect free programs.

All clojure datastructures are immutable, meaning that they can’t be changed. You want to modify a vector, list, map or set, the fundamental datastructures, you instead return a new one. This is a very cheap operation since the new datastructure shares memory space with the old one.

You can change “variables” though. But in Clojure, a variable just binds a name to a datastructure. Since all data structures are immutable, this name represents a snapshot of something at a given time. Rich Hickey, Clojure creator and benevolent dictator explains that in the most simple way possible:

At a certain point in time, Marco’s phone number was 1234–5678. But lost his phone and has a new phone number: 1111–2222. He didn’t change the old number, he’s got a new one. But we still call it Marco’s phone number. This is how binding works in clojure.

By a language that praises pureness and side effect free programs, we can say that Clojure makes it harder to write mutable, implicit, imperative code. But Clojure knows that a program designed to solve real world problems has to deal with side effects, like printing to output, reading the file system or writing to a database. That’s why Clojure has functions designed to make side effects like do doseqand dotimes. These are some of the few standard lib’s functions that don’t need to return something (altough they actually return nil ). Clojure code is very explicit on where to put side effects.

Data Structures

In addition to various types of numbers, the nil type that you can think as being null, and strings, which are already immutable in languages like Java and C#, you are going to work a lot with Clojure collections.

Collections are immutable, persistent and abstract. You cannot change the value of a collection, instead you return a new one. But the new one shares memory space with the last one (that’s why its called persistent), so it’s a very cheap operation. And abstract because Clojure operations on collections like map filter and reduce don’t care about the type of collection its working on, therefore these methods works uniformily among them.

Most of the time we are going to work with one of the four core collection types: vectors, lists, sets and maps.

Vectors

From clojure.org:

Vectors are an indexed, sequential data structure. Vectors are represented with [ ] like this:
[1 2]

You can think about vectors like Java/C# arrays. They are indexed meaning that you can get an item by index:

You can add a new item to an array using the conj function. It will add the item to the end of the array:

Lists

From clojure.org:

Lists are sequential linked lists that add new elements at the head of the list, instead of at the tail like vectors.

Lists are represented by ( ) like ("Brazil" "France" "Italy") .

Adding items to a list:

Do you see the ' before (".cs" ".js") ? Quote is the non evaluation operator. You might have noticed that the function calling in clojure is done with the same parenthesis as lists. That’s because a clojure program is actually a “List Processing” (LISP) dialect, so it’s represented by a bunch of lists (and other datastrutures, like vectors, maps…). So when Clojure sees a list, it tries to evaluate the first item as a function and the rest as the function arguments, as in (inc 1). This is a function called inc with 1 as its unique argument. It returns 2, because it increments the number 1. To differ function calls from functions declarations, i.e. (inc 1) from (1 2) we need to quote a list, so Clojure doesn’t try to call the first item of the list as a function.

You can retrieve items from a list in different ways:

Sets

Sets are collections with unique values. They are represented by #{ } as in #{1 2 3} . Here are some operations on sets:

Maps

Maps are collections that maps keys to values. They are represented by alternating keys and values surrounded by{ } as in {:name "Marco" :job "Software Engineer"} . You can split key/value pairs with commas, to improve readability as in {:name "Marco", :job "Software Engineer"} since clojure treats commas as white spaces.

Operations on maps are pretty similar to what you have seen in previous collections. Maps are great to store domain data. You can think of them as Javascript’s object literals (without the prototype), PHP’s associative arrays, and if you come from Java/C#, you would use them like DTOs/POCOs/POJOs.

Functions

Knowing the basic datastructures, we can go forward and talk about another basic concept. It’s functional programming after all. We’ve already called lots of functions in this article. Clojure tries to call every first list item as a function, passing the following items as its arguments. As said before, that’s why sometimes you need to define lists with a quote, so Clojure doesn’t try to evaluate it as a function.

This is part of Clojure awesomeness. Theres no syntax difference between calling functions and defining lists. And since there’s not much else besides functions and datastructures, including lists, you can do pretty much everything with the syntax you have already seen in the article.

Let me show that:

In line one, we are calling the if function. It evaluates the boolean result of its second argument (= (+ 1 2) 3 ) , and if it’s true, it returns the third argument, the "Equals 3" string, or else it returns the fourth argument, the "Not equals 3"string.

Let’s dive into the second argument: (= (+ 1 2) 3 ) . We call the = function, that returns true when both arguments are equal. The first argument is (+ 1 2) . We are calling the + function, which sums all its arguments, and therefore it returns 3, so (= (+ 1 2) 3 ) returns true, and the if function evaluates to true, printing Equals 3 .

See, we just added numbers and compared its equalities in a conditional statement with no new syntax to learn. This is pretty much Clojure. You can deep dive as you want, and yes, there are more syntax constructs, advanced language features like macros, atoms, agents, namespaces, protocols and multimethods, but you can conquer the world with just functions and datastructures.

A function is called in clojure in the following form:

(function-name param1 param2 paramN)

Functions are defined with the fn form, an vector of arguments and its body:

(fn [name] (str "Hello, " name))

We defined a function that receives a single argument, the symbol name, and returns the concatenation of Hello, with the name argument. If we call it with the “Marco” argument, it would print Hello, Marco . We can call it by puting it inside a list, passing the function definition as first argument, and a string as second argument.

((fn [name] (str "Hello, " name)) "Marco")

There’s no name bounded to this function, therefore it’s an anonymous function.

But lets give this function a name, to bind it with a symbol, and make it callable, using the def function:

(def greet [name] (fn (str "Hello, " name))

There’s a shortcut to that, the defn form:

(defn greet [name] (str "Hello, " name))

We just binded the greet symbol to the previous function, and now we can call it with:

(greet "Marco") ;returns "Hello, Marco"

There’s also the shortcut for anonymous functions, using the # syntatic suggar before the list, as in #( ) . Arguments are indicated by the % syntax, and if the anonymous function accepts more than one argument, they should be numbered as in #(print %1 %2) . This is an anonymous function that prints it’s two arguments.

The most obvious anonymous function usage is passing them to to functions that accepts another functions as arguments, like map filter and reduce.

For example, the map function accepts two arguments, a function that will be called with the current collection item being iterated as its only argument, and the collection to map:

(map #(inc %) [1 2 3])

We called the map function with an anonymous function as its first argument and a vector as its second argument. The anonymous function calls the inc[rement] function on its unique argument. The map function iterates through the collection and passes each item to the anonymous function. Therefore this functions returns [2 3 4]

Reduce is another function that receives an function as an argument, and a collection as its second argument. We use this function to reduce a collection to a single value:

(reduce #(+ %1 %2) [1 2 3 4 5])

reduce expects an function that receives an accumulator as the first argument, and the current collection item as the second argument. It applies the result of the function to the accumulator, and them passes the new accumulated value to the function and next collection item. In this example we are applying the plus function + to the accumulated value, the first argument as in %1 and the second argument as %2, the current collection item:

First iteration: apply + to 1 and 2. Accumulated: 3.

Second iteration: apply + to the accumulated (3) and 3. Accumulated: 6.

Third iteration: apply + to the accumulated (6) and 4. Accumulated: 10;

Fourth iteration: apply + to the accumulated (10) and 5. Final result: 15.

Now that we know some basic datastructures, functions and the clojure syntax, the first code you’ve seen in the article beginning might be more familiar:

At line for, we are concatenating two vectors, resulting in [1 2 3 4 5 6] . At line 3 we map its items through an anonymous functions that multiplies each item by 3, resulting in [3 6 9 12 15 18] . At line 2 we filter this vector with an anonymous function, a predicate, that returns only the even items, using the = and mod funcitons, resultin in [6 12 18] . Then we reduce this collection to a single value containing the sum of all its values, resulting in 36 .

See, there’s almost no syntax to learn. Through this article, we have: added, multiplied, compared equality, defined functions, made conditional statements, with the exact same syntax: lists. Isn’t this amazing? Its like you almost don’t need to learn Clojure: you already know it!

Resources to dive deeper

Through this article I have ommited some details and I might have not been exactly accurate in defining some concepts, for simplicity sake. The goal of this article was to desmytify the idea that Clojure is hard to learn. It’s the simplest getting started that I could possibly share.

There are great free resources to get a deeper getting started, with more accurate and complete information. Clojure Distilled is one of the best to get to know some concepts. The official website and doc pages are also great. If you are a video guy like me, the ClojureTV Youtube channel has lots of interesting talks. Clojurians is an awesome Slack channel with plenty of people willing to help. Awesome Clojure is a Github repository with some useful clojure libraries. The Clojure Newbie Guide has some great resources for getting started.

Seamless start with Docker and REPL

Since Clojure runs on the JVM, you need Java, JDK, etc, installed. You would also need to install Leiningen, the clojure package manager. And probably an IDE or text editor. I’ve found that IntelliJ Community + Cursive extension make a great Clojure development environment.

But there’s a way to start playing with Clojure without installing any of those. You can use the Clojure REPL (Read-Eval-Print-Loop) with a simple docker command. The REPL evaluates code on the go, so you don’t even need to create a file. If you have docker installed just type docker run -it clojure lein repl . It will download the clojure image, and start a container with the repl command. Try to type (+ 1 2) and see what happens!

Clojure is a functional programming language in which programs are represented by data strucutres. Since there’s almost no syntax to learn besides the datastrutures themselves, Clojure is one of the simplest languages out there. The language gets more and more awesome as you dive deeper into its details. Take a look at the resources showed previously in the article if you feel like it. You will never think about programming the same way as before.

--

--