Clojure风格(以及一般的良好软件工程)强调许多小功能,其中一部分是公开可见的,以提供外部接口。
在Clojure中,似乎有几种方法可以做到这一点:
(letfn [(private-a ...)
(private-b ...)]
(defn public-a ...)
(defn public-b ...))
(defn- private-a ...)
(defn- private-b ...)
(defn public-a ...)
(defn public-b ...)
letfn形式似乎更冗长,也许更不灵活,但它减少了函数的范围。
我的猜测是,当只在很小的区域内使用小辅助函数时,letfn仅用于其他形式。这是共识吗?是否应该在顶层使用(正如我以前推荐的那样)?什么时候应该使用?
答案 0 :(得分:11)
letfn
旨在用于相互递归的情况:
(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
不要在顶层使用它。
除非您有非常具体的原因,否则请勿在除顶级以外的任何地方使用defn
宏。它将扩展为def
特殊形式,它将创建和实习全局变种。
答案 1 :(得分:4)
letfn
的目的与defn
形式的目的完全不同。在顶层使用letfn
并不会提供相同的defn属性,因为在letfn
内绑定的函数的名称绑定在其范围之外是不可见的。绑定在let
或letfn
内的函数的绑定在其词法范围之外不可用。此外,绑定在letfn
内的函数的可见性与它们在该词法范围内绑定的顺序无关。 let.
答案 2 :(得分:3)
我的规则是:
let
或letfn
。defn-
在顶层定义它。 和
let
或letfn
。def
或defn
或defn-
。