13
votes

I'm new to clojure, and I've seen anonymous functions written like:

(fn [x] (* x x))

and also like:

#(* % %)

Obviously, the second is more concise. Is there any relevant difference? Can every anonymous function be represented in either style? Is one more idiomatic?

Related to this question, I was unable to determine how to convert (fn [x] [x x]) to the latter syntax. I would appreciate a pointer to documentation that clarifies this situation.

3
#() does not have an implicit do. (fn [] ... ) does.Bill
To elaborate on @Bill's comment: stackoverflow.com/questions/12534287/…noahlz

3 Answers

21
votes

The most important differences are:

  • (fn ...) can be nested, #() cannot
  • You can name your parameters better with (fn [x y] ..) or similar, rather than using %, %2, %3 etc.
  • You can name a function with (fn ...) for recursive usage, e.g. (fn fib [n] (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))
  • It's easier to do code generation/manipulation (fn [...] ...) since #() is a reader macro rather than a regular Clojure form.
  • #() is more concise. But if that is a major consideration, you probably have your priorities wrong :-)

Personally my advice would be:

  • Prefer (fn [...] ...) in most circumstances
  • Use #() only for very short inline functions, e.g. (map #(+ 2 %) (range 10))
  • Also consider that it may be better to generate anonymous functions via higher-order functions rather than writing them out explicitly e.g. (comp func1 func2) or (partial func param1 param2) etc.
4
votes

Another SO answer (Common programming mistakes for Clojure developers to avoid) mentions that #([% %]) expands to fn [%] ([% %]) (note the parentheses), which causes an ArityException.

You can do #(vector % %) to workaround this limitation.

2
votes

From the docs, i think that these are the most relevant differences:

idiomatic used would be for very short one-off mapping/filter fns and the like.

#() forms cannot be nested.

Another thing is that if you need named parameters, fn is a better option. For the #() you will use % or, for more the one parameters, something like %1, %2 and so on (also %&).