Use `letfn` when a computation needs named helper functions that should remain local. Like a combination of `let` and `fn`, it binds functions within a body, but every bound function can refer to every other one—even functions named later in the binding vector. This makes mutual recursion possible without namespace-level definitions. section 3.1.3 section 2.1.1
The shape is `(letfn [(name [params] exprs...) ...] body...)`. Each function needs a name and a parameter vector, which may be empty and may use destructuring. A function with no expressions has an implicit `nil` body. `letfn` returns the result of its body, or `nil` when no body is supplied. section 3.1.3
Name a small local operation
`(letfn [(square [x] (* x x))] (map square (range 10)))` returns `(0 1 4 9 16 25 36 49 64 81)`. The name makes the mapping operation readable without extracting `square` into the namespace. section 3.1.3
Refer to a later function
`(letfn [(even? [n] (or (zero? n) #(odd? (dec n)))) (odd? [n] (and (not (zero? n)) #(even? (dec n))))] (trampoline odd? 120))` returns `false`. Both names are visible throughout the bindings; the example uses `trampoline` to run their mutually recursive calls. section 3.1.3
(defn locs-xform [match]
(letfn [(matching? [ns] ; #1
(re-find
(re-pattern match)
(str (ns-name ns))))
(var->sym [{:keys [ns name]}]
(symbol (str ns) (str name)))
(count-lines [fsym]
(count
(clojure.string/split-lines
(or (clojure.repl/source-fn fsym) ""))))]
(comp ; #2
(filter matching?)
(map ns-interns)
(mapcat vals)
(map meta)
(map var->sym)
(map (juxt identity count-lines)))))
A transducer can keep its main pipeline compact by naming the private operations that match namespaces, construct symbols, and count source lines. section 3.1.3
Choose `letfn` for helpers substantial enough to name but not general enough to expose. Unlike ordinary `let` bindings, its function names are mutually visible. Be careful when reusing a name in nested `letfn` forms: a self-reference can call the inner function rather than the outer one and cause a `StackOverflowError`. `letfn*` supplies the underlying special form; there is no particular reason to use it directly. section 3.1.3 section 3.1
