One of my favorite things about Clojure is that there are just so many really neat, useful functions and macros built into the language, and I’m constantly learning about new ones that I didn’t know existed. I thought I would share with you some of my favorites. If you’re a Clojure programmer, you’ve probably already used at least a handful of these (maybe even all of these), but hopefully there is at least one function here that will be new to you.
Without further ado, and in no particular order:
1) into
into
does something really simple, but in a really nice, intuitive way; it takes two collections and adds the contents of the second collection “into” the first. Under the hood, it’s basically just doing (reduce conj first-coll second-coll)
, but the very fact that this function exists as a clojure.core function can make code so much neater-looking and concise. I most commonly find myself using it to convert a collection of key-value vectors into a map, like so:
You can also use it to easily convert from one collection type to another, as in the following examples:
2) mapv (added in Clojure 1.4)
Another simple helper function, mapv
works just like map
, except that it returns a vector instead of a list. Interestingly enough, if you look at the source for mapv
, you can see that the arities of this function that take multiple collections are actually just calling (into [] (map ...
3) pmap
pmap
is another variant of map
; it works just like map
, but it can be useful for computationally intensive functions by coordinating the application of the function over the items in the collection so that they are executed in parallel.
Stealing an example from ClojureDocs:
4) mapcat
While I’m on the subject of map
variants, mapcat
is a handy one that takes the result of mapping a function (presumably one that returns a collection) over a collection, and then applies concat
to the results. So it’s really just a shortcut for (apply concat (map ...
5) empty
Not to be confused with empty?, which returns whether or not a collection is empty, empty
returns an empty collection that is the same type as its argument:
This is mainly useful if you’re trying to write a function that returns the same type of collection as its argument. For example, let’s say we want to write a function that applies inc
to each item in a collection. If our definition was just (map inc coll)
, our function would return a list every time, regardless of the collection type of the argument. We can fix this using into
and empty
:
(This is a bit of a contrived example, and not a perfect one – (inc-each '(1 2 3))
would actually return (4 3 2)
due to the way that into
works, and the fact that conj
-ing items into a list adds them onto the front rather than the back. But you get the idea!)
6) fnil
fnil
is a “function modifier” – it takes any function, and returns a modified version of that function that will replace its nil
arguments with a value of your choosing.
This is surprisingly handy, as it enables you to easily create functions with default values, like this:
Another cool thing about fnil
is that it enables a “hash-map with default value” behavior. In Ruby, you can create a hash that has a default value that will always be returned when trying to get the value of a key that doesn’t exist in the hash:
In Clojure, you can mimic this functionality using fnil
:
Because ({} "TLC")
returns nil
and not 0, we use fnil
to turn inc
into a function that works just like inc
unless its argument is nil
, in which case it acts like it’s working with 0
. This is especially nice (and arguably better than default hash values in Ruby) because we could define additional functions that also use fnil
to work with different default values, while still working with the same hash-map; this gives us the possibility of different default semantics for different functions, and without requiring that the hash-map be “set up” in any way to have default values.
7) juxt
juxt
takes two or more functions and returns a function that returns a vector containing the results of applying each function on its arguments. In other words, ((juxt a b c) x) => [(a x) (b x) (c x)]
. This is useful whenever you want to represent the results of using 2 different functions on the same argument(s), all at once rather than separately:
This function is especially powerful when dealing with multimethods, as it provides a concise way to dispatch on multiple parameters:
8) partial
partial
is a neat little function that some might consider a “functional programming must-have.” It takes a function that takes a specific number of arguments, and the values for only some of those arguments as parameters, and returns a function that will take the remaining parameters.
A common use for partial
is to create a modified version of a function with “default” arguments:
9) comp
comp
provides a nice, succinct way of expressing the composition of two or more functions. To steal an example from ClojureDocs:
10) iterate
The next few functions provide easy ways to create infinite lazy sequences. iterate
takes a function and a starting value and returns a lazy sequence consisting of the starting value, the function applied to the starting value, the function applied again to that second value, the function applied again to that third value, ad infinitum.
Among the many cool things you can do with iterate
is the creation of an infinite sequence of Fibonacci numbers. (example shamelessly stolen from ClojureDocs):
11) cycle
cycle
returns a lazy sequence of the items in a collection, repeating in sequence forever. For instance, (cycle "dave")
returns the infinite sequence (\d \a \v \e \d \a \v \e \d \a ...)
etc. Among the things we can do with cycle
is writing a function that produces a list of all the rotations of a given collection:
12) repeat
When given only one argument, repeat
returns a lazy sequence of an infinite number of that thing given as an argument. When given a number, it returns that number of that thing.
13) repeatedly
repeatedly
works just like repeat
, except that it takes a function instead of a value as the thing to repeat. It then calls the function (which must take no arguments, and presumably has side effects) repeatedly and returns a lazy sequence of its values.
14) constantly
This is an interesting function that returns a function which takes any number of arguments and then ignores them and returns a particular value of your choosing.
This function will come in handy if you ever encounter a situation where you’re using a function that expects a function as an argument, but you really want to provide a constant value instead of a function.
To give you a real-world example, I recently found constantly
useful when I was using instaparse to construct and transform a parse tree. Instaparse’s transform function takes a map of node-types (as keywords) to functions used to transform their contents. I had nodes representing flats and sharps, their content being strings like "flat"
, "b"
or "f"
for flat, "s"
or "sharp"
for sharp. I wanted each node to be transformed into the strings "-flat"
or "-sharp"
, regardless of what variation was parsed as a flat or sharp node.
15) get-in
The next few functions are useful whenever you’re working with nested data structures. get-in
provides an easy way to obtain values from within a nested collection:
As you can see, this works not only with maps, but also with vectors, which act like maps with indices as keys.
Just like with get
, you can supply any value as a final argument to get-in
in order to return it (instead of nil) if the specified key is not found:
16) assoc-in
You can use assoc-in
to return a modified version of a nested data structure with one of the values changed:
As with assoc
, you can use assoc-in
to create fields that didn’t already exist:
17) update-in
update-in
is a lot like assoc-in
, except that instead of providing a value, you provide a function to transform the existing value at a particular place in your nested date structure.
18) read-string
These next three functions are fun and a little dangerous if you aren’t careful. They can be useful in metaprogramming contexts, although typically macros will provide a safer and more flexible way to do whatever you’re trying to do.
read-string
takes a string as an argument and reads one object from the string. The contents of the string are assumed to be valid Clojure code.
Of note, read-string
will compile an object, but will not evaluate it. If you give it a string like "(+ 1 1)"
, read-string
will read it in as a list containing +
, 1
and 1
.
19) eval
eval
evaluates a form data structure (i.e. a list of functions and arguments that can be run as Clojure code) and returns the result.
20) load-string
load-string
essentially does the same thing as (eval (read-string ...
, except that read-string
will only read one object from a string, whereas load-string
will sequentially read and evaluate the set of forms contained within a string.