Functions and Lists

By now we've used several different functions, but we haven't yet made one. As a simple exercise, we will make a function called square that takes a number as an argument and returns that number multiplied by itself. So, (square 2) should give us 4. You can make a function using fn:

(fn [n] (* n n))

When we use fn, we must give it a vector of symbols representing the arguments. It could have zero or more, but in this case there is only one, which we call n. Then we get to the body of the function, which multiplies n by itself.

The only problem is, fn creates a function object, but there is no var we can refer to it with, so it's a bit hard to use. We can solve this using the same def mechanism we've used in the past:

(def square (fn [n] (* n n)))

Now we can call it:

(square 2) (square 3) (square 10)

It turns out that we need to define functions all the time, so there is a shorthand built into the language:

(defn square [n] (* n n))

So, defn does the equivalent of the def + fn combo above, but with a bit less typing. It's nice to see how it works underneath – it's just making a function object and saving it to a var.

Let's return to our set of digits:

(def digits #{\1 \2 \3 \4 \5 \6 \7 \8 \9 \0})

We can now write a function that tells us if a given character is a digit. In Clojure it is common for functions that return a boolean (true or false) to end in a ?, so we'll call it digit?, and the argument will be called ch (short for "character"):

(defn digit? [ch] (contains? digits ch))

And it can be called as you would expect:

(digit? \7) (digit? \u)

Let's bring back our vector of characters:

(def chars (vec "42 0.5 1/2 foo-bar"))

We know we can pull out individual values with get, but how could we just run our digit? function on every character? For that, we use map:

(map digit? chars)

There is also a closely related function that will use our digit? function to decide which characters to keep, and thus discard non-digit characters:

(filter digit? chars)

Or, if you want to do the opposite:

(remove digit? chars)

Notice something subtle about what these functions are returning. We've seen that normally data is stored in vectors as [...], but these functions are returning their values between parens. That's because they are lists, not vectors.

There are many underlying differences between lists and vectors, but the most interesting difference for now is that lists can be lazy, delaying how their values are computed until the latest possible time.

For now, however, you should stick to using vectors as much as possible. You can always convert a list to a vector with the same vec function we've used before:

(vec (filter digit? chars))

There are also versions of map and filter that return vectors automatically:

(mapv digit? chars) (filterv digit? chars)

One more thing about lists. We've seen before that we can make a vector of digits by writing [\1 \2 \3], and a set of digits by writing #{\1 \2 \3}, but we can't do the equivalent for lists:

(\1 \2 \3)

We get an error! That's because the evaluator, as we saw previously, tries to call a function whenever it sees parens, and \1 is not a function. In a sense, parens serve "double duty" in Clojure. They invoke functions, and they represent lists. That means, if we want to create a list, we need to "shut off" the evaluator.

We already learned how to do this. Just as we can put a single quote before a symbol to make it stay a symbol, we can put one before a list to make it stay a list:

'(\1 \2 \3)

Another option is to create a list with the list function:

(list \1 \2 \3)

Nonetheless, for most day-to-day tasks, you should stick with vectors when you want an ordered collection, and sets when you want to check if it contains a value. Lists aren't that useful of a data structure in most cases.

Previous: Vectors and SetsNext: Conditions