6

当我有与独立于其参数的函数相关的数据时,我应该在什么时候支持块封装而不是本地封装?

我什么时候应该使用:

(let [hello "Hello "]
  (defn do-greet
    "Print a greeting."
    [name]
    (println (str hello name))))

相对:

(defn do-greet
  "Print a greeting."
  [name]
  (let [hello "Hello "]
    (println (str hello name))))
4

4 回答 4

6

如果您想在词法范围的代码块中使用静态常量之类的值,则前者是一个合理的选择。通常,如果出现以下情况,您会这样做:

  • 该值的计算成本很高,并且您只想在加载命名空间时执行一次
  • 该值是真正的常量,即不会在函数调用之间改变
  • 该值将在多个函数定义中使用(即您将多个定义放在 let 块内)
  • (可能?)因为您想在宏扩展中使用值,并且在宏扩展本身中嵌入 let 会增加不必要的复杂性。

在大多数其他情况下,可能应该首选后一个版本,这有几个原因:

  • 它更地道
  • 它允许函数定义处于顶层,这对代码的可读性/理解性更好
  • 它允许值在不同的函数调用上有所不同
  • 它更好地反映了在本地上下文中使用该值的意图
于 2012-11-03T04:21:06.770 回答
5

这是一种风格上的选择,而且应该至少在一定程度上取决于计算价值的成本。改为考虑:

(defn nth-prime [n] ...)

(defn f [x]
  (let [factor (nth-prime 10000)]
    (* x factor)))

(let [factor (nth-prime 10000)]
  (defn g [x]
    (* x factor)))

每次f调用都重新计算一个昂贵的常量是浪费的,并且g使用一种简单的技术来避免这样做。

于 2012-11-02T20:49:55.617 回答
2

如果hello仅在该单个函数中使用,则将其放在let函数本身内部更有意义。如果您要在多个函数中使用,那么将这些函数的外部包裹起来是hello有意义的。let

于 2012-11-02T20:07:08.650 回答
1

绝对是这个:

(defn do-greet
  "Print a greeting."
  [name]
  (let [hello "Hello "]
    (println (str hello name))))
于 2012-11-02T19:14:02.067 回答