Clojure Basics

When learning a new language I like to collate the bare minimum amount of syntax and language information in order to start playing around with it by solving Project Euler Problems.

This is for my own reference really, but hopefully it could be handy for someone else going along the same path. Its really the absolute minimum that you’d need to start having fun.

Table of Contents

  1. Basic Syntax
    1. Forms
    2. Operations
    3. Control Flow
      1. if
      2. cond
      3. do
      4. when
      5. and
      6. or
    4. Data Types
      1. Strings
      2. Numbers
    5. Data Structures
      1. Lists
      2. Vectors
      3. Maps
      4. Sets
      5. Keywords
    6. Core functions
      1. def
      2. cons
      3. conj
      4. first
      5. next
      6. rest
      7. nth
      8. take
      9. drop
      10. complement
  2. Writing Functions
    1. The Structure of a Function
    2. Arity
      1. Using Arity Overloading to provide default arguments
      2. Rest parameter
    3. Destructuring
      1. Vectors
      2. Maps
    4. Anonymous Functions
    5. Threading
  3. Tests
    1. Writing and running tests
    2. Asserts
    3. lein-test-refresh
    4. test.check
  4. Functional Tools
    1. Apply
    2. Partial
    3. Map
    4. Reduce
    5. Filter
    6. Comp
    7. Memoize
  5. Namespaces
    1. What are namespaces?
    2. Creating namespaces
    3. Alias
  6. Macros
    1. What are Macros?

Please note that several of the code examples in this are reworked examples from one of the following:

Basic Syntax


Forms are the basis of Clojure’s syntax. These include:

  • operations

  • literal representations of data, such as:
    • strings
    • numbers
  • data structures, such as:
    • lists
    • vectors
    • maps


In Clojure operations all take the form of: open-parenthesis, operator, operands, close-parenthesis

    (operator operand-a operand-b)

Control Flow


Clojure has conditionals to control flow, such as if, which has the following structure:

    (if operation-that-returns-Boolean

Notice that the operator if takes takes three operands here. The first is resolves to a Boolean. If this is truthy then the first of the two possible branches will be evaluated (in this case then-do-this). Otherwise, the other branch, else-do-this will be evaluated.

Having the other branch is optional, much like an else term in Ruby or Python. If no alternate branch is provided, when the conditional is evaluated as false, Clojure will return nil.

  1. Truthy and Falsey expressions:
  • Falsey: false , nil
  • Truthy: true , everything else

Notably, the number 0 is a truthy expression in Clojure.


The cond function is for a switch-like control flow. Each condition is stated, followed by the result of that condition.

    (defn pos-neg-or-zero
      "Determines whether or not n is positive, negative, or zero"
        (< n 0) "negative"
        (> n 0) "positive"
        :else "zero"))
    (pos-neg-or-zero 5)
    ;=> "positive"
    (pos-neg-or-zero -1)
    ;=> "negative"
    (pos-neg-or-zero 0)
    ;=> "zero"


The do operator allows you to evaluate multiple expressions in order.

    (do (+ println "hello")
        (+ println "hello again!"))
    ;=> hello
    ;=> hello again!
    ;=> nil

Here we have used **println** to print a string as a line.
the **;=>** symbols represent the output of evaluating this **do** expression.
Here each of the sub-expressions have been executed. 
Finally, the return value of the last sub-expression is returned.
(**println** expressions return **nil**)

<a id="orgc45d601"></a>

### when

the **when** operator works like a **if** operator, 
but with no optional second branch. Therefore **when** always returns nil when the Boolean is falsey.
**when** also allows you to evaluate multiple expressions, like **do**.

    (when true
      (println "multiple")
      (println "expressions"))
    ;=> multiple
    ;=> expressions
    ;=> nil


The and operator returns the first falsey value, or if there are no falsey values, the last truthy one.

    (and false true)
    ;=> false
    (and (= "a" "a") true 1 0 "last one")
    ;=> "last one"
    (and 0 "my string" nil true)
    ;=> nil


The or operator returns the first truthy value, or if there are no truthy values, the last value

    (or false true)
    ;=> true
    (or 1 0 "last one")
    ;=> 1
    (or 0 "my string" nil true)
    ;=> 0

Data Types


Strings are surrounded in double quotes. A backslash can be used to escape special characters.

    (println "let's print some double quotes: \"\"\"")
    ;=> let's print some double quotes: """
    ;=> nil

The function str can be used to make a single string out of multiple string.

    (def first_part "This is the beginning, ")
    (println (str (first_part "and this is the end.")))
    ;=> This is the beginning, and this is the end.
    ;=> nil


Clojure handles integers, floating point numbers and ratios nativity.

    (+ 1.5 2)
    ;=> 3.5
    (* 1/2 1/3)
    ;=> 1/6

Data Structures


Lists are collections of values. Lists in Clojure use parentheses, and so look a lot like functions. In order to signify that we are using a list rather than a function to be evaluated, we put a single quote in-front of the list.

    '(1 2 3 4)
    ;=> (1 2 3 4)

Note that there is no need for commas between items of a list. Functions such as **first**, **last** and **nth** can be used on lists.

    (first '(1 2 3 4))
    ;=> 1
    (last '(1 2 3 4))
    ;=> 4
    (nth '(1 2 3 4) 2)
    ;=> 3

Note that nth’s second argument is the value of n, which is 0-indexed.


Vectors are like lists in some ways, however they have some different properties. They do not require a single quote in-front of of them. They use square braces. Rather than using nth, items can be pulled from a vector using get.

    (get [1 2 3 4] 0)
    ;=> 1

Vector elements can be of any type. As with lists.


Maps are analogous to hashes in Ruby, or dictionaries in Python. They are contained in curly braces and key, value pairs are simply added in that order.

    (def my-map {:first-key "the first one" :second-key "another one"})
    (println (my-map :second-key))
    ;=> another one

Map values can be of any type. Strings, numbers, nested maps, functions. Anything.


Sets are collections of unique values. They can ether be hash-sets or sorted sets. Hash-sets are formatted like so:

    #{:a :b "another item" 12}
    ;=> #{"another item" 12 :b :a}

Note how it doesn’t retain it’s order.

Calling hash-set on a number of data objects will return a hash-set of them, excluding duplicates.

    (hash-set 1 5 2 5 7)
    ;=> #{7 1 2 5}


Keywords are mainly used as keys in maps. They always evaluate to themselves.

    ;=> :test-keyword
        (def my-map {:a 1 :b 2})
        (:a my-map))
    ;=> 1

Core functions


the def operator binds a name to a value in Clojure. Generally it is preferable to not re-assign a new value to a name in Clojure.

    (def super-example "this is my great example")
    (println super-example)
    ;=> this is my great example


Prepends an item to a list.

    (cons 1 '(2 3 4 5 6))
    ;=> (1 2 3 4 5 6)


Adds an item to a collection. If it’s a vector, the new item will be added at the end. If it’s a list it’ll be added at the beginning.

    (conj [1 2 3] 4)
    ;=> [1 2 3 4]
    (conj '(1 2 3) 4)
    ;=> (4 1 2 3)


Returns the first item in a sequence.

    (first '(:alpha :bravo :charlie))
    ;=> :alpha


Returns all apart from the first item in a sequence. If the sequence contains only one item next will return nil.

    user=> (next '(:alpha :bravo :charlie))
    ;=> (:bravo :charlie)
    user=> (next (next '(:one :two :three)))
    ;=> (:three)
    user=> (next (next (next '(:one :two :three))))
    ;=> nil


Like next but always returns a sequence.

    (rest [1 2 3 4 5])           
    ;=> (2 3 4 5)
    (rest '())
    ;=> ()


Returns value at index n.

    (def my-seq ["a" "b" "c" "d"])
    (nth my-seq 0)
    ;=> "a"
    (nth my-seq 1)
    ;=> "b"
    (nth [] 0)
    ;=> IndexOutOfBoundsException ...
    (nth [] 0 "nothing found")
    ;=> "nothing found"
    (nth [0 1 2] 77 1337)
    ;=> 1337


Takes the first n items from a sequence.

    ;; return a lazy seq of the first 3 items
    (take 3 '(1 2 3 4 5 6))
    ;=> (1 2 3)


Discards the first n items from a sequence. Returns a list

    (drop 2 [1 2 3 4])
    ;=> (3 4) 


Complement simply inverts the return value of a function that returns a Boolean.

    (defn my-even-test
      (even? x))
    (def my-odd-test (complement my-even-test))
    (my-odd-test 1)
    ;=> true

Writing Functions

The Structure of a Function

A main parts of a function are the following:

  • defn
  • The function’s name.
  • A description of the function (aka a docstring).
  • The parameters listed in square brackets.
  • The body of the function.
    (defn my-new-addition-function
      "This is a function that takes two numbers and sums them."
      [first-number second-number]
      (+ first-number second-number))
    (my-new-addition-function 3 5)
    ;=> 8

Functions can contain any number of forms. All the forms will be evaluated, unless there are conditionals inside the function. The evaluation of the last form will be the return value of the function.

    (defn many-forms-one-return
      (+ 1 1)
      (+ 1 2)
      (/ 1 2)
      (- 9 3))
    ;=> 6


A function’s arity is the number of parameters it takes. Clojure functions support arity overloading, which is polymorphism controlled by the arity of the function.

Airty overloading is added to a function by providing each arity definition in parentheses. Each definition includes an argument list, followed by a function body.

    (defn my-multi-arity-function
      ([one two three]
       (println "Three arguments!"))
      ([one two]
       (println "Two arguments!"))
       (println "One argument!")))
    (my-multi-arity-function 666 "frogs")
    ;=> Two arguments!

Using Arity Overloading to provide default arguments

Since a function can call itself recursively, arity overloading can be used to provide default arguments.

    (defn func-with-default-arg
    	(println (str "here a number for you: " number-to-print)))
    	(func-with-default-arg 99)))
    (func-with-default-arg 100)
    ;=> 100 
    ;=> 99

Rest parameter

A function can take an unspecified number of arguments. Kind of like argv in a c-style language. Clojure uses an ampersand & followed by a name to signify a rest parameter in the argument list. Named individual arguments can be put before the rest.

    (defn func-using-rest
        [named-arg-a named-arg-b & other-args]
        (println (str "A is : " named-arg-a " and B is : " named-arg-b 
    		  " and the rest sum to: " (reduce + other-args))))
    (func-using-rest 10 20 1 2 3 4 5)
    ;=> A is : 10 and B is : 20 and the rest sum to: 15



The same rest principle can be applied to vectors passed as arguments. We can simply name consecutive items in the vector, followed by a rest parameter.

    (defn destruct-vec
      [[first second & rest] another-arg arg-three]
      (println (str "the second item in the vector is " second
    		" and you also passed " another-arg " and "
    (destruct-vec [99 "frog" :keyname] "floop" "gloop")
    ;=> the second item in the vector is frog and you also passed floop and gloop


There are several methods for destructuring maps. We can name the keys, like so:

    (defn destruct-map-1
      [{first-key :a second-key :b}]
      (+ first-key second-key))
    (destruct-map-1 {:a 10 :b 20})
    ;=> 30

We can also detructure the keys using the :keys keyword.

    (defn destruct-map-2
      [{:keys [first-key second-key]}]
      (+ first-key second-key))
    (destruct-map-1 {:a 1/2 :b 1/4})
    ;=> 3/4

Anonymous Functions

Anonymous functions, sometimes known as lambda expressions or simply lambdas, are available in Clojure. Here are a couple of syntaxes for lambdas:

    ((fn [a b]
       (* a b)) 9 100)
    ;=> 900
    (#(* % 3) 2)
    ;=> 6

Using the hash syntax we can also give rest parameters. He we have done so, also using the reduce function to sequentially apply the addition.

    (#(reduce + %&) 1 2 3 4 5)
    ;=> 15 

The above is a contrived example to show the lambda using a rest parameter. We will revisit reduce below.


Nesting operations within operations can become difficult to read. The threading syntax can make things clearer.

Thread first and thread last are two different syntaxes to represent this. Thread first uses a ->, Whereas thread last uses a .

    (defn not-threaded
      (even? (* 7 (inc a))))
    (defn thread-first
        (inc a)
        (* 7)
    (defn thread-last
        (* 7)
        (inc a)))


Writing and running tests

Tests are usually put in test directory, at the same level as the src directory in a Clojure project.

Naming convention is to have the same name as the src file, appended with _test.


Tests are simply functions that take no arguments. They are declared like so:

    (deftest my-test
      (println "Here is a test!"))

Tests can be run from the REPL:


Also, all a project’s tests can be run from a shell.

    $ lein test


An assert in a test can be written with an is. Additional structure can be added with a testing block. Details of the test can be added with an optional string argument to the is.

    (defn my-test
      (testing "let's begin our tests!"
        (is (= 1 2) "tests if one is equal to two")))
    ;=> FAIL in (my-test)
    ;=> let's begin our tests!
    ;=> tests if one is equal to two
    ;=> expected: (= 1 2))
    ;=> actual: (not (= 1 2))


This is a Leiningen plugin that live-refreshes tests after you save a file.

To install add this to your plugins in ~/.lein/profiles.clj

    [com.jakemccrary/lein-test-refresh "0.23.0"]

To run it in the shell:

    $ lein test-refresh


Functional Tools


The apply function allows us to treat the items in a sequence as arguments to a function. For example.

    (max 2 4 6 8 10)
    ;=> 10
    (apply max [2 4 6 8 10])
    ;=> 10


The partial function can be used to make higher order functions.

    (def splitter (partial * 0.5))
    (splitter 3)
    ;=> 1.5


Applies a function to each item in a sequence. If more than one sequence is passed then each corresponding value by index is passed as an argument simultaneously. Returns a lazy sequence.

    (map inc [1 2 3 4 5])
    ;=> (2 3 4 5 6)
    (map + [1 2 3] [4 5 6])
    ;=> (5 7 9)


Applies a two argument function across a sequence. Takes the outcome of the previous function all and the next consecutive item in the sequence. This is done repeatedly until the sequence is empty.

    (reduce + [1 2 3 4 5]) 
    ;=> 15
    (reduce + [])          
    ;=> 0
    (reduce + 1 [2 3])     
    ;=> 6


Filters a sequence by a predicate.

    (filter even? (range 10))
    ;=> (0 2 4 6 8)
    (filter #(= (count %) 1)
      ["a" "aa" "b" "n" "f" "lisp" "clojure" "q" ""])
    ;=> ("a" "b" "n" "f" "q")


This is used to compose functions from multiple other functions.

    ((comp inc *) 2 3)
    ;=> 7

In a quasi-mathematical notation, we can compose functions…

… to create a new function, g, such that:

Note the above will not be rendered correctly in GitHub flavour markdown.


This will save the outcome of a function call provided with specified arguments.

    user=> (defn myfunc[a] (println "doing some work") (+ a 10))
    user=> (def myfunc-memo (memoize myfunc))
    user=> (myfunc-memo 1)
    ;=> doing some work
    ;=> 11
    user=> (myfunc-memo 1)
    ;=> 11
    user=> (myfunc-memo 20)
    ;=> doing some work
    ;=> 30
    user=> (myfunc-memo 20)
    ;=> 30


What are namespaces?

Namespaces in Clojure are simmilar to namespaces in C++. They can contain mappings between symbols and values. The current namespace can be refered to like so:


We can see a namespace’s name with the ns-name function. If we were to use this in the REPL, by default we’d get the following response.

    (ns-name *ns*)
    ;=> user

When an object is stored with def, this is added to the current namespace.

Again, we can see this in the REPL:

    (def my-obj {:a "value 1" :b "value 2"})
    ;=> user/my-obj

We can all of a namespace’s mappings of symbols using ns-interns

    (ns-interns *ns*)
    ;=> my-obj #'user/my-obj

Creating namespaces

A namespace can be made with create-ns.

    (create-ns my-new-namespace)

However, it can be more convenient to switch to a new namespace once it’s made. This can be done in a single command, like so:

    (in-ns my-super-namespace)

If the namespace name already exists, the above will simply cause you to move into the given namespace.


The alias function can be used to give an abbreviated version of a namespace in order to refer to fully qualified symbols more easly.

Suppose we are in the my-super-namespace created above, and we want to refer to the object we previously made in the user namespace using an alias:

    (clojure.core/alias 'u 'user)
    ;=> {:a "value 1" b: "value 2"}


What are Macros?

Macros allow the compiler to be extended with user code. Several of Clojure’s core constructs which would be primatives in other languages are in fact macros in Clojure. For example when is a macro. We can see this by using macroexpand.

    (macroexpand '(when (pos? a) (println "positive") (/ b a)))
    ;=> (if (pos? a) (do (println "positive") (/ a b)))

Here we can see that when is in fact a macro that uses if and do.

Macros are like functions, but they take arguments without evaluating them. Here is a superflous ‘macro’, which is really just behaving like a function.

    (defmacro plus-func
      [a b]
      (+ a b))
    (plus-func 1 2)
    ;=> 3

It serves no perpose for this function to be declared with defmacro. It should be just a regular function.

Since macros allow us to take arguments without evaluating them, we can use them to alter the expected behaviour of lists.

    (defmacro infix
    ; Here destructuring is used to name the items in the passed list.
      [[first-arg second-arg third-arg]]
      (second-arg first-arg third-arg))
    ; Now we can perform simple additions with infix, rather than prefix notation.
    (infix (1 + 2))
    ;=> 3	
Written on January 9, 2019