Function Syntax in Clojure
When I was first learning Clojure, I found the shorthand syntax for anonymous functions to be a bit confusing. Hopefully this little write up on the different ways to define functions will help someone out. If you're just looking for a refresher on the anonymous function shorthand, skip right to the bottom.
If you're spent some time with Clojure, it's likely that you're familiar with the standard function definition:
(defn my-func [arg1 arg2] (... function body here ...))
Which is a shorthand for
(def my-func (fn [arg1 arg2] (... function body here ...)))
You can easily make a non-public function by using defn-
(defn- my-func [arg1 arg2] (... function body here ...))
There are a lot of circumstances where you might not need to actually define a function; you might just want to use it once, for a particular purpose, and then throw it away. That's where anonymous functions come in. You may be familiar with them in Javascript and Ruby, where anonymous functions are often used as callbacks.
You've already seen the basic anonymous function definition in the second example above.
(fn [arg1 arg2] (... function body here ...))
This function is anonymous because it's not bound to a particular name using def. This definition alone isn't very useful: it needs context.
A simple example, concatenating the two arguments into a single string. You could do something like this:
((fn [arg1 arg2] (str arg1 arg2)) "A" "B")
Because of the outermost parentheses the anonymous function is executed immediately and passed the two arguments "A" and "B", ultimately returning "AB"
This still isn't a very practical example. In Clojure, you'll often see anonymous functions passed as arguments to other functions. In the case of the map
function, it accepts a function as its first argument and a collection as its second. That function argument doesn't need to be a language defined function or a user defined function, it can be anonymous. You could do something like this:
(map (fn [arg1] (str "Hello: " arg1)) ["A" "B"])
The map
function applies the anonymous function to each element in the collection ["A" "B"]
and returns ("Hello: A" "Hello: B")
That's a relatively simple anonymous function, but you can probably see that it's already getting a bit hard to read. Enter the shorthand syntax for anonymous functions. Let's reproduce the last anonymous function using the shorthand syntax.
#(str "Hello: " %)
It's a lot less verbose than the original, but it's also not completely intuitive. Let's break it down. The #()
syntax is what tells Clojure that this is a function. It's pretty much equivalent to (fn [] ())
.
The %
symbol is used as a shorthand to reference the arguments passed to the function, so that you don't clutter the function definition by explicitly naming them. Both %
and %1
will reference the first argument passed in, %2
will reference the second argument, and so on.
Our shorthand #(str "Hello: " %)
is the same as (fn [arg1] (str "Hello: " arg1))
Clojure will pay attention to how many arguments your shorthand anonymous function is expecting and complain if it receives the wrong number of arguments. For example:
(#(str "Hello:" % " and " %2) "A")
This function expects 2 arguments, but receives only one, causing Clojure to say:
ArityException Wrong number of args (1) passed to: user$eval740$fn clojure.lang.AFn.throwArity (AFn.java:437)