12
votes

In Clojure, when and why does one want to use a named anonymous function? E.g.,

((fn add-five [x] (+ x 5)) 3))

In ClojureDocs, one example's comment says that it is useful in stack traces. Can one give an example of that?

3

3 Answers

10
votes

There are two reasons to name anonymous functions (or at least two reasons that I've done so). The first is that giving it a name tells a later reader (perhaps yourself 6 months down the line) what the heck that anonymous function is supposed to do.

The second is (as you mention) to have better information in a stack trace to point you at the right location in your code when a failure occurs. Functions are compiled into classes and the class name includes a (munged) version of the function name. When you have a stack trace, it will include that class name and thus point you semantically towards the proper location.

user=> (filter (fn [x] (/ 100 x)) [100 50 0])
ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:158)
user=> (pst *e)
ArithmeticException Divide by zero
    clojure.lang.Numbers.divide (Numbers.java:158)
    clojure.lang.Numbers.divide (Numbers.java:3784)
    user/eval8/fn--9 (NO_SOURCE_FILE:3)
    clojure.core/filter/fn--6908 (core.clj:2790)
    ...
nil

user=> (filter (fn hundred-div [x] (/ 100 x)) [100 50 0])
ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:158)
user=> (pst *e)
ArithmeticException Divide by zero
    clojure.lang.Numbers.divide (Numbers.java:158)
    clojure.lang.Numbers.divide (Numbers.java:3784)
    user/eval14/hundred-div--15 (NO_SOURCE_FILE:5)        ;; <---
    clojure.core/filter/fn--6908 (core.clj:2790)
    ...
7
votes

Apart from being useful in stacktraces, I suppose you could use it when you need an anonymous function to be recursive, as it would be able to call itself.

For instance:

(fn factorial[n]
  (if (<= n 1)
    1
    (* n  (factorial (- n 1)))))

Although recursing like this in Clojure is a bit dangerous, as it could potentially cause stack overflows.

5
votes

Named anonymous functions can be useful when they refer to themselves, and also by being printed with their name:

user=> ((fn [] (throw (Exception. "unnamed"))))

Exception unnamed  user/eval805/fn--806 (NO_SOURCE_FILE:1)
user=> ((fn myfn [] (throw (Exception. "named"))))

Exception named  user/eval809/myfn--810 (NO_SOURCE_FILE:1)