Clojure style: defn- vs. letfn



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只用于其他表单中。这是共识吗?letfn是否应该在顶级级别上使用(正如我之前看到的建议)?什么时候应该使用?

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特殊形式,它将创建和实习生全局变量

letfn的用途与defn表单的用途完全不同。在顶级使用letfn不会为您提供相同的defn属性,因为在letfn内部绑定的函数的名称绑定在其范围之外是不可见的。绑定在letletfn内部的函数的绑定在其词法范围之外不可用。此外,绑定在letfn内部的函数的可见性与它们在该词法范围内的绑定顺序无关。let. 的情况并非如此

我的规则是:

  • 如果在一个公共函数中使用子函数,请定义它与CCD_ 12或CCD_
  • 如果它用于多个,请使用defn-在顶层定义它

  • 不要在顶级使用letletfn
  • 不要在顶级以外的任何地方使用defdefndefn-

最新更新