Intro to Clojure

A short intro to Clojure, many thanks to Clojure Bridge for most of the material.

Notice the parentheses. Parentheses enclose instructions to the computer in Clojure. A left parenthesis is the start of the instruction, and a matching right parenthesis is the end of the enclosing instruction. Clojure code has a lot of nested parentheses.

Next to the parentheses, we see the instructions to the computer. That instruction is normally what we call a function. The functions do all the hard work in Clojure. print-str, + and forward are all functions. When these functions get run, they return a some type of value. Clojure functions always return a value.

Simple Values

Strings

What is a string? A string is just a piece of text. To make a string, you enclose it in quotation marks. Look at the last example. A backslash is how we put a quotation mark inside a string. Do not try using single quotes to make a string.

   "Hello, World!"
   "Aubrey said, \"I think we should go to the Orange Julius.\""
        

Booleans and nil

A boolean is a true or false value, and you type them just like that, true and false. Often in programming, we need to ask a true or false question, like “Is this class in the current semester?” or “Is this person’s birthday today?” When we ask those questions, we get a boolean back. There is another value nil, which behaves like a boolean in terms of truthiness. But, nil means no value at all and not a boolean

   true
   false
   nil
        

Keywords

Keywords are the strangest of the basic value types. Some computer languages have similar one. However, keywords don’t have a real world analog like numbers, strings, or booleans. You can think of them as a special type of string, one that’s used for labels. They are often used as keys of key-value pair for maps (data structure; will learn later).

   :trinity
   :first
   :last
        

Numbers

Clojure has several different types of numbers. First up are integers. Integers include zero, the positive whole numbers, and the negative whole numbers, and you write them just like we write them normally.

   0, 12, -42
      

Then we have decimal numbers, which are also called floats. They include any numbers that have a decimal point in them.

   0.0000072725, 10.5, -99.9
      

Finally, we have fractions, which are also called ratios. Computers cannot perfectly represent all floats, but ratios are always exact. We write them with a slash, like so: Note that, just like with pen-and-paper math, the denominator of your ratio cannot be equal to 0.

   1/2, -7/3
        

Infix vs. prefix notation

In Clojure, +, -, * and / appear before two numbers. This is called prefx notation. What you’re used to seeing is called infx notation, as the arithmetic operator is in-between the two operands.

Explicit precedence

Imagine both are unclear, but notice that in the prefix version, you do not have to ever think about the precedence of operators. Because each expression has the operator before all the operands and the entire expression is wrapped in parentheses, all precendence is explicit.

This example uses integers but try changing the numbers to floats, decimals, or fractions and see what happens.

See how this infix example is written in Clojure in the editor below.

Infix: 1 + 2 / 3

Less repetitive

Another reason prefix notation can be nice is that it can make long expressions less repetitive. With prefix notation, if we plan to use the same operator on many operands, we do not have to repeat the operator between them.

See how this infix example is written in Clojure in the editor below

Infix: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9

Some basic Clojure functions

str this example combines two strings, but try changing one of them to a number.

inc

Data Structures

So far, we’ve dealt with discrete pieces of data: one number, one string, one value. When programming, it is more often the case that you want to work with groups of data.

Vectors

A vector is a sequential collection of values. A vector may be empty. A vector may contain values of different types. Each value in a vector is numbered starting at 0, that number is called its index. The index is used to refer to each value when looking them up.

Vectors are written using square brackets with any number of pieces of data inside them, separated by spaces. Here are some examples of vectors:

The next two functions are used to make new vectors. The vector function takes any number of items and puts them in a new vector. conj is an interesting function that you’ll see used with all the data structures. With vectors, it takes a vector and an item and returns a new vector with that item added to the end of the vector. Why the name conj? conj is short for conjoin, which means to join or combine. This is what we’re doing: we’re joining the new item to the vector.

Now, take a look at these four functions.

count gives us a count of the number of items in a vector.

nth gives us the nth item in the vector. Note that we start counting at 0, so in the example, calling nth with the number 1 gives us what we’d call the second element when we aren’t programming.

first returns the first item in the collection.

rest returns all except the first item.

concat

Maps

Maps hold a set of keys and values associated with them. You can think of it like a dictionary: you look up things using a word (a keyword) and see the definition (its value). If you’ve programmed in another language, you might have seen something like maps–maybe called dictionaries, hashes, or associative arrays.

We write maps by enclosing alternating keys and values in curly braces, like so. {:first "Sally" :last "Brown"} Maps are useful because they can hold data in a way we normally think about it. Take our made up example, Sally Brown. A map can hold her first name and last name, her address, her favorite food, or anything else. It’s a simple way to collect that data and make it easy to look up.

This is an empty map. Add some key-value pairs!

assoc and dissoc are paired functions: they associate and disassociate items from a map. See how we add the last name “Mitchell” to the map with assoc, and then we remove it with dissoc.

merge merges two maps together to make a new map.

count every collection has this function. Why do you think the answer is two? count is returning the number of associations.

Since map is a key-value pair, the key is used to get a value from a map. One of the ways often used in Clojure is the examples below. We can use a keyword like using a function in order to look up values in a map.

Then we have keys and vals, which are pretty simple: they return the keys and values in the map. The order is not guaranteed, so we could have gotten (:first :last) or (:last :first).

Simple values such as numbers, keywords, and strings are not the only types of things you can put into collections. You can also put other collections into collections, so you can have a vector of maps, or a list of vectors, or whatever combination fits your data.

Now you know how to do Clojure lets make some beautiful animation! Go to the Quil tutorial.→

At the request of the survivors, the names have been changed. Out of respect for the dead, the rest has been told exactly as it occurred