85
votes

There's something I don't understand about anonymous functions using the short notation #(..)

The following works:

REPL>  ((fn [s] s) "Eh")
"Eh"

But this doesn't:

REPL>  (#(%) "Eh")

This works:

REPL> (#(str %) "Eh")
"Eh"

What I don't understand is why (#(%) "Eh") doesn't work and at the same time I don't need to use str in ((fn [s] s) "Eh")

They're both anonymous functions and they both take, here, one parameter. Why does the shorthand notation need a function while the other notation doesn't?

4

4 Answers

126
votes
#(...)

is shorthand for

(fn [arg1 arg2 ...] (...))

(where the number of argN depends on how many %N you have in the body). So when you write:

#(%)

it's translated to:

(fn [arg1] (arg1))

Notice that this is different from your first anonymous function, which is like:

(fn [arg1] arg1)

Your version returns arg1 as a value, the version that comes from expanding the shorthand tries to call it as a function. You get an error because a string is not a valid function.

Since the shorthand supplies a set of parentheses around the body, it can only be used to execute a single function call or special form.

65
votes

As the other answers have already very nicely pointed out, the #(%) you posted actually expands to something like (fn [arg1] (arg1)), which is not at all the same as (fn [arg1] arg1).

@John Flatness pointed out that you can just use identity, but if you're looking for a way to write identity using the #(...) dispatch macro, you can do it like this:

#(-> %)

By combining the #(...) dispatch macro with the -> threading macro it gets expanded to something like (fn [arg1] (-> arg1)), which expands again to (fn [arg1] arg1), which is just want you wanted. I also find the -> and #(...) macro combo helpful for writing simple functions that return vectors, e.g.:

#(-> [%2 %1])
21
votes

When you use #(...), you can imagine you're instead writing (fn [args] (...)), including the parentheses you started right after the pound.

So, your non-working example converts to:

((fn [s] (s)) "Eh")

which obviously doesn't work because the you're trying to call the string "Eh". Your example with str works because now your function is (str s) instead of (s). (identity s) would be the closer analogue to your first example, since it won't coerce to str.

It makes sense if you think about it, since other than this totally minimal example, every anonymous function is going to call something, so it'd be a little foolish to require another nested set of parens to actually make a call.

0
votes

If you're in doubt what your anonymous function gets converted to, you can use the macroexpand procedure to get the representation. Remember to quote your expression before passing it to macroexpand. In this case we could do:

(macroexpand '#(%))
# => (fn* [p1__281#] (p1__281#))

This might print different names for p1__281# which are representations of the variables %.

You can also macroexpand the full invocation.

(macroexpand '(#(%) "Eh"))
# => ((fn* [p1__331#] (p1__331#)) "Eh")

Converted to more human readable by replacing the cryptic variable names by short names. We get what the accepted answers have reported.

# => ((fn* [s] (s)) "Eh")

Resources: