Clojure风格:defn-与letfn

时间:2014-04-23 21:44:28

标签: clojure coding-style

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仅用于其他形式。这是共识吗?是否应该在顶层使用(正如我以前推荐的那样)?什么时候应该使用?

3 个答案:

答案 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内绑定的函数的名称绑定在其范围之外是不可见的。绑定在letletfn内的函数的绑定在其词法范围之外不可用。此外,绑定在letfn内的函数的可见性与它们在该词法范围内绑定的顺序无关。 let.

的情况并非如此

答案 2 :(得分:3)

我的规则是:

  • 如果在一个公共功能中使用辅助功能,请对其进行定义 本地使用letletfn
  • 如果在多个中使用它,请使用defn-在顶层定义它。

  • 不要在顶层使用letletfn
  • 请勿在顶级以外的地方使用defdefndefn-