Clojure style (and good software engineering in general) puts emphasis on lots of small functions, a subset of which are publicly visible to provide an external interface.
In Clojure there seem to be a couple of ways to do this:
(letfn [(private-a ...)
(private-b ...)]
(defn public-a ...)
(defn public-b ...))
(defn- private-a ...)
(defn- private-b ...)
(defn public-a ...)
(defn public-b ...)
The letfn form seems more verbose and perhaps less flexible, but it reduces the scope of the functions.
My guess is that letfn is intended only for use inside other forms, when little helper functions are used in only a small area. Is this the consensus? Should letfn ever be used at a top level (as I've seen recommended before)? When should it be used?
letfn
is intended for use in cases of mutual recursion:
(letfn [(is-even? [n]
(if (zero? n)
true
(is-odd? (dec n))))
(is-odd? [n]
(if (zero? n)
false
(is-even? (dec n))))]
(is-even? 42))
;; => true
Don't use it at the top level.
Also don't use the defn
macro anywhere else than at the top level unless you have very specific reasons. It will be expanded to the def
special form which will create and intern global var.
The purpose of letfn
is totally different from the purpose of defn
form. Using letfn
at the top level does not give you same properties of defn, since any bindings of names to functions bound inside letfn
is not visible outside its scope. The binding for functions bound inside let
or letfn
is not available outside its lexical scope. Also, the visibility of functions bound inside letfn
is independent of the order in which they are bound inside that lexical scope. That is not the case with let.
My rules are these:
let
or letfn
.defn-
. And
let
or letfn
at top level.def
or defn
or defn-
anywhere other than top level. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With