A Very Short Introduction to Clojure
Tags: programming, introduction, clojure
Published: 2022-11-14 16:48:38

This guide is not meant to make any arguments about why to learn Clojure but is only meant to give a very quick introduction to syntax basics. I think Clojure is a very elegant language, but the "weird" syntax often puts people off. I will attempt to show so you some basics so you can get an idea of what Clojure looks and feels like.

⚠️ Warning: This guide leaves out a bunch of details and makes some oversimplifications for the sake of brevity. It also assumes that you are comfortable with basic programming concepts.⚠️

## Trying It Out

If you want to code along and run any of the following code on your computer then the easiest way to do that is with the REPL. 

Just install Clojure (see the [official guide](https://clojure.org/guides/install_clojure)) and type `clojure` in your terminal. 

This will start an interactive environment in which you can run Clojure code. 

You can verify everything is working by running `(println "Hello, World!")`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6oq2osoxdv8wcztafnc.jpg)

## Invoking Functions

If you ran the above snippet, you already invoked your first function, but it is worth looking at the anatomy of a Clojure function invocation. 

```clojure
(function-name arg-1 arg-2 ... arg-n)
```

The parentheses instruct Clojure to invoke a function where the value in the first position is the function name, and the remaining values are arguments to that function.

```clojure
(+ 1 2) ;=> 3
```

In the above example, `+` is the function and `1` and `2` are the arguments, resulting in the value `3`. 
If you try this in the REPL then the result will be printed to the terminal.

## Defining Variables

You can use `def` if you need to store a value in an easier-to-remember name.

To keep things simple, you can think of these being defined globally.

```clojure
(def x 10)
(def y 15)
(+ x y) ;=> 25
```

## Defining Functions

To define functions, you use `defn`. The generic structure of a function definition looks like this.

```clojure
(defn function-name
  [arg-1 arg-2 ... arg-n]
  body-expression-1
  body-expression-2
  ...
  body-expression-n)
```

For example, following function takes a name and prints a personalised greeting. 

```clojure
(defn greet
  [name]
  (println "Hello there, " name))

;Call the function you just created
(greet "Alice") 
;"Hello there, Alice
;=> nil
```

Two lines are printed because the greeting is printed to the console with `println` and so is the return value of the function.
Every function returns a value and in this case, the function returns `nil` (Clojure's version of a `null` value).

The value of the last expression within a `defn` is the return value.  For example, you could return the name of the greeted person. 

```clojure
(defn greet
  [name]
  (println "Hello there, " name)
  name)

(greet "Alice") 
;Hello there, Alice
;=> "Alice"
```

## Define Scoped Variables

To define locally scoped variables, you can use `let`. 

```clojure
;a will only be available within the parenthesis of the let
(let [a 1]
  (println a)) ;=> 1

;a is not available anymore
(println a) ;=> Unable to resolve symbol: a in this context
```

You can define multiple variables within a single let too.
```clojure
(let [a 1
      b 2]
   ...)
```

You can, for example, extract the greeting from our above example into a variable to print and return it.

```clojure
(defn greet
  [name]
  (let [greeting (str "Hello there, " name)]
    (println greeting)
    greeting))
```

## Sequencial Collections

The most straightforward list collection to use are vectors. 
You can create one like this.

```clojure
(def names ["Alice" "Andrew"])
```

Values within a vector are separated by spaces and you can mix types, but you probably should not. 

You can print greetings for a list of names.

```clojure
(defn greet
  [name]
  (println "Hello there," name))

(def names ["Alice" "Andrew" "R2-D2"])

(for [name names]
  (greet name))
;Hello there, Alice
;Hello there, Andrew
;Hello there, R2-D2
```

Or only greet the first name in the list

```clojure

(greet (first names))
; Hello there, Alice
```

## Maps

The second core collection is a map that is useful for storing key-value pairs. You can use anything you like as a key or value.

A simple person map could look like this

```clojure
(def person 
  {"name" "Alice"
   "age" 20})
```

And a value can be accessed with the `get` function.

```clojure
(get person "name") ;=>Alice
```

This works just fine, but often there is a better type you can use for keys and those are so called `keywords`. A keyword is, more or less, an identifier with special attributes and written with a leading colon, e.g. `:name`.

One of the best attributes of keywords is, that they can be used as lookup functions.

```clojure
(def person 
  {:name "Alice"
   :age 20})

;This works
(get person :name) ;=>Alice

;But this is neater
(:name person) ;=Alice
```

## Basic Control Flow

One of the simplest control flow construct in most languages is `if-else`. 

In Clojure the generalised version looks like this. 

```clojure
(if test-expression
  then-expression
  else-expression)
```

Let's say you want to modify our greeting for anyone over the age of 50.

```clojure
(defn build-greeting
  [person]
  (if (> (:age person) 50)
    (str "Good Evening, " (:name person))
    (str "Hey there, " (:name person))))

(build-greeting {:name "Andrew" :age 51})
=> "Good Evening, Andrew"

(build-greeting {:name "Alice" :age 20})
=> "Hey there, Alice"
```

## Putting it together

Let's write a bit of code that prints greetings for a list of people. 

```clojure

(def people [{:name "Alice"
             :age 20}
            {:name "Andrew"
             :age 55}])

(defn build-greeting
  [person]
  (if (> (:age person) 50)
    (str "Good Evening, " (:name person))
    (str "Hey there, " (:name person))))

(defn greet-all
  [people]
  (for [person people]
    (let [greeting (build-greeting person)]
      (println greeting))))

(greet-all people)
;Hey there, Alice
;Good Evening, Andrew
```

Congrats! You now know the basics of Clojure.

If you want to learn more then I can recommend the following resources: 
 * [Official Getting Started Guide](https://clojure.org/guides/getting_started)
 * [Clojure for the Brave and True](https://www.braveclojure.com/foreword/) (Free Online Book)
 * [Programming Clojure](https://a.co/bSxW6A6) (Book)