See Some Clojure
Published: 2021-01-23 15:40:54

---
title: See Some Clojure
published: true
date: 2021-01-19 00:00:00 UTC
tags: 
canonical_url: https://www.rakeroutes.com/see-some-clojure
---

Have you seen any Clojure code?

Yes? You’ll almost certainly not see anything new or interesting here.

No? Let’s change that! I’m certainly not an expert: but I’ve been reading “Getting Clojure” by Russ Olsen so I at least know enough to give a quick tour.

## Basics

Hello!

```
(println "Hello World")
```

Not too weird yet. There’s parentheses around the line but it’s not too far from something like `print "Hello World"`.

But here, the following line adds up the integers 1 through 4.

```
(+ 1 2 3 4) ; 10
```

If you’ve never seen a Lisp language then this probably looks weird. Clojure is my first Lisp dialect and sure looked strange to me at first. But I was surprised to find how quickly I came to appreciate the clear structure of the parentheses.

[![xkcd Lisp Cycles comic](https://blot.im/cdn/blog_a48c2be3d1364623b1c4d68dc80015b4/_image_cache/fcc41a59-e388-40e3-a520-d1992b068396.png)xkcd Lisp Cycles comic](https://xkcd.com/297/)

As a Lisp dialect, the syntax of Clojure is structured data in parentheses. To make anything _happen_ in Clojure it’s gotta be in parentheses.

Comments in Clojure are prefixed with a semicolon (a double semicolon conventionally for lines that are entirely comments).

The structure of every (as far I have seen) Clojure call

```
(function arg0 arg1 arg2 arg3 … argN)
```

With that knowledge in mind we can make sense of that first `(+ 1 2 3 4)` line. The `+` function is being called with the arguments `1 2 3 4`. The equivalent line In a non-Lisp language would be `1 + 2 + 3 + 4`.

One of the major foundations of Clojure is that **everything** is done via functions. Arithmetic, variable assignment, logic, conditionals, and even key lookups in a map are done by treating the key as a function.

```
;; Arithmetic
(+ 1 2 3) ; 6
(/ 6 2) ; 3
(/ 24 2 3) ; 4

;; Variable Assignment
(def greeting "Hello")

;; Logic
(= 2 3) ; false
(= 2 2 2) ; true
(> 9 7 3) ; true
(> 9 4 5) ; false

;; Conditionals
(def a 9)
(def b 3)
(if (> a b) a b) ; 9

;; Map lookup
(def zork1 {:released 1980 :genre :text-adventure})
(:released zork1) ; 1980
(:genre zork1) ; :text-adventure
```

You’ll notice that a bunch of those functions take more arguments than you may expect. In many languages equality is a two argument expression e.g. `a == b` but in Clojure you can compare an arbitrary number of arguments quite expressively.

## Conditionals

In Clojure conditionals are _also_ functions. The `if` function is called with 2 (optionally 3) arguments.

- If the first argument evaluates to `true` then the second argument is evaluated and its result becomes the result of the entire statement.
- If the first argument evalulates to `false` then the result is `nil` OR the optional third argument is evaluated.

```
user=> (if (= 2 2) "yes 2 equals 2")
"yes 2 equals 2"

user=> (if (= 2 3) "yes 2 equals 2")
nil
```

Now the `if` statement from before can make more sense.

```
(if (> a b) a b)
; ⌃⌃⌃⌃⌃⌃⌃ ⌃ ⌃
; │ │ │
; └────── first arg: the logic to evaluate
; │ │
; └──── second arg: evaluated if first arg is true
; │
; │
; └── third arg: evaluated if first arg is false
```

## Variables

Defining variables in Clojure is a function as well. The `def` function accepts a name and anything that evaluates to a value.

```
user=> (def number 123)
#'user/number

user=> number
123

user=> (+ number 4)
127
```

## Functions

As a functional language, functions are naturally at the heart of Clojure. They can be defined with the `fn` function which accepts a vector (basically an array) of arguments followed by statements to evaluate. The last statement’s result will be the returned result of calling the function.

```
(fn [n] (* 2 n))
```

We can assign that function to a name with `def`

```
user=> (def doubler (fn [n] (* 2 n)))
#'user/doubler

user=> (doubler 3)
6

user=> (def printy-doubler (fn [n] (println "Doubling" n) (* 2 n)))
#'user/printy-doubler

user=> (printy-doubler 3)
Doubling 3
6
```

Using `def` and `fn` works but is not great experience that Clojure wants its programmers to have. Clojure provides the `defn` function to easily name and define a function in one call.

```
user=> (defn tripler [n] (* 3 n))
#'user/tripler

user=> (tripler 3)
9
```

The theme of providing useful functions for common actions is a major feature of Clojure. It provides many functions simply to make its programming more concise, expressive, and joyful.

## Common Data Structures

Clojure has the commonly used data structures you should expect from a modern programming language.

As a functional language Clojure has immutable data structures. If you aren’t familiar with their use the quick gist is that whenever you manipulate data such as adding a new item to a list then you don’t mutate that list: a new list is created with the additional item.

### Vectors

An ordered collection of items in a continuous block of memory (i.e. an array) that are defined with brackets.

```
[1 2 3 "four" ["any data even another vector"]]

(def v [1 2 3 4])
(count v) ; 4
(first v) ; 1
(rest v) ; (2 3 4)
```

### Lists

Lists are also an ordered collection of items, but rather than being stored in a continuous block of memory they are implemented as linked lists. That has ramifications for when it’s appropriate to use either data structure: e.g. it’s trivial to add a new item to the beginning of a list but relatively expensive to add a new item to the beginning of a vector.

In practice vectors are far more commonly used.

Lists are defined with parentheses which means they need a slight tweak over what we’d expect so Clojure doesn’t confuse them with expressions: we need to prepend them with `'`

```
'(1 2 3 "four" ("a nested list"))

(def l '(1 2 3 4))
(count l) ; 4
(first l) ; 1
(rest l) ; (2 3 4)
```

### Commas?

You may have noticed above that neither vectors nor lists used commas between the values. Clojure neatly does away with any comma arguments by treating them as whitespace. You can use them if you must but the common approach is to simply omit them.

```
;; these vectors are all the same data
(= [1 2 3 4] [1,2,3,4] [1,,,,,2,3,4] [1,2,3 4]) ; true

;; commas are whitespace even for expressions
(+,1,2,3,4) ; 10
(+,1,2,3,4,) ; 10
```

### Maps

Data structures that associate keys and values (i.e. dictionaries or hashes). Note commas aren’t required between sets of key/values (because commas are whitespace).

Any value can be a key but Clojure programs usually use **keywords** as keys e.g. `:keyword`. Keywords can be used as functions themselves to retrieve values from a map.

```
;; a bare map
{:key "value" :another-key "another value"}

;; assigned to a variable
(def ps5 {:name "Playstation 5" :publisher "Sony" :released 2020})

(:publisher ps5) ; "Sony"
(keys ps5) ; (:name :publisher :released)

(conj ps5 {:output :hdmi})
;; {:name "Playstation 5", :publisher "Sony", :released 2020, :output :hdmi}

ps5
;; {:name "Playstation 5", :publisher "Sony", :released 2020}
```

Note that the `conj` (conjoin) function above does not modify the ps5 variable. It returns a new map with the additional data.

## Documentation

Clojure has inline documentation you can access in its repl.

```
user=> (doc conj)
-------------------------
clojure.core/conj
([coll x] [coll x & xs])
  conj[oin]. Returns a new collection with the xs
    'added'. (conj nil item) returns (item). The 'addition' may
    happen at different 'places' depending on the concrete type.

user=> (doc +)
-------------------------
clojure.core/+
([] [x] [x y] [x y & more])
  Returns the sum of nums. (+) returns 0. Does not auto-promote
  longs, will throw on overflow. See also: +'

user=> (doc doc)
-------------------------
clojure.repl/doc
([name])
Macro
  Prints documentation for a var or special form given its name,
   or for a spec if given a keyword
```

## Wrapping Up

You’ve now seen some Clojure! This isn’t even close to a comprehensive overview of this powerful and expressive language. Clojure has many more constructs to help write powerful programs simply.

If you’re interesting in learning more I highly recommend Russ Olsen’s [Getting Clojure](https://pragprog.com/titles/roclojure/getting-clojure/) from the Pragmatic Programmers.