What is the "name?" argument in Clojure's fn?

Viewed 108

I am reading the book "Getting Clojure" by Russ Olsen. In chapter 8, "Def, Symbols, and Vars", there is the following function definition:

(def second (fn second [x] (first (next x))))
                ^^^^^^

My question is regarding the underlined second, which comes second.

At first, I thought this syntax is wrong as anonymous functions don't need a name. But as it turnes out, this syntax is correct.

Usage: (fn name? [params*] exprs*)
       (fn name? ([params*] exprs*) +)

I tried comparing the following two function calls.

user> (fn second [x] (first (rest x)))
#function[user/eval5642/second--5643]
user> (fn [x] (first (rest x)))
#function[user/eval5646/fn-5647]

Besides the name of the function, there does not seem to be a difference.

Why would there be a name? argument to fn?

2 Answers

You can use it when creating multiple arities:

(fn second
      ([x] (second x 1))
      ([x y] (+ x y)))

or if you need to make a recursive call:

(fn second [x] (when (pos? x)
                  (println x)
                  (second (dec x))))

There are two main usages:

  • recursive functions (you now know the name)
user=> ((fn foo [x] (when (pos? x) (println x) (foo (dec x)))) 3)
3
2
1
nil

  • better stacktraces (the name will give you a better hint, where things went wrong)
user=> (map (fn bar [x] (inc x)) ["a"])
Error printing return value (ClassCastException) at clojure.lang.Numbers/inc (Numbers.java:137).
java.lang.String cannot be cast to java.lang.Number
user=> (pst)
ClassCastException java.lang.String cannot be cast to java.lang.Number
      clojure.lang.Numbers.inc (Numbers.java:137)
      user/eval8020/bar--8021 (NO_SOURCE_FILE:1)
      clojure.core/map/fn--5866 (core.clj:2753)
      clojure.lang.LazySeq.sval (LazySeq.java:42)
      clojure.lang.LazySeq.seq (LazySeq.java:51)
      clojure.lang.RT.seq (RT.java:535)
      clojure.core/seq--5402 (core.clj:137)
      clojure.core/seq--5402 (core.clj:137)
      puget.printer.PrettyPrinter (printer.clj:529)
      puget.printer/iseq-handler--1663 (printer.clj:314)
      puget.printer/iseq-handler--1663 (printer.clj:312)
      puget.printer/format-doc* (printer.clj:223)

(note user/eval8020/bar--8021)

Related