Clojure风格:defn-与letfn

ryb*_*ern 7 coding-style clojure

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 ...)
Run Code Online (Sandbox Code Playgroud)

letfn形式似乎更冗长,也许更不灵活,但它减少了函数的范围.

我的猜测是,当只在一个小区域内使用小辅助函数时,letfn仅用于其他形式.这是共识吗?是否应该在顶层使用(正如我以前推荐的那样)?什么时候应该使用?

Leo*_*hin 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
Run Code Online (Sandbox Code Playgroud)

不要在顶层使用它.

defn除非您有非常具体的原因,否则不要在除顶级以外的任何地方使用宏.它将扩展为def将创建和实习全局变量的特殊形式.

  • 将 `letfn` 用于一般辅助函数绝对没有错,包括在顶层。Pedestal 的[数据流引擎](https://github.com/pedestal/pedestal-app/blob/master/app/src/io/pedestal/app/dataflow.clj#L46)就是一个例子。我没有附属 - 只是可信的 Clojure 人员的“严肃”项目中的一个随机示例。 (2认同)

grd*_*vnl 6

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