2012-11-02 210 views
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)))) 

回答

6

如果您想在词法范围的代码块中使用类似静态常量的值,前者是合理的选项。通常,你可以这样做,如果:

  • 价值是昂贵的计算,并且要做到这一点,只有当命名空间加载一次
  • 值真正恒定,即不会在函数调用
  • 改变
  • 该值将在多个函数定义中使用(即,您在let块中放置多个defns)
  • (可能?),因为您要使用宏扩展内的值,并将let嵌入到宏扩展本身会增加不必要的复杂性

后者版本或许应该在其他大多数情况下是首选,这是很好的有以下几个原因:

  • 更地道
  • 它允许函数的定义是在顶层,这对代码可读性/理解性更好
  • 它允许在不同的函数调用中改变该值
  • 它更好地反映了在本地环境中使用该值的意图
+0

我喜欢这个,你覆盖更多的观点。我不确定你的宏观扩展点是否有效,因为你可以围绕扩展进行展开,但仍然在函数内部。为了便于阅读,我建议将语言选择与语义差异分开。 (值可能因不同的函数调用而异)。 – bmillare

1

肯定这一点:

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

如果hello在一个单一的功能,才使用它更有意义把let放入函数本身。如果您打算在多种功能中使用hello,那么将let置于外围并包裹这些功能是有意义的。

+0

如果两者在运行时不相等,我认为我们不应该仅仅根据样式来决定。想象一下,绑定是为了读一个静态资源'(let [hello(slurp(clojure.java.io/resource“hello”))] ...)'。我把我的问题留给了更一般的人,因为我不知道这些表格如何评估以及相应的折中。 – ToBeReplaced

+1

在某些情况下,它与风格没有任何关系。如果需要使用两个不同功能的值,则必须使这些值超出这些功能的范围。另请参阅@ amalloy的答案。 – Rayne

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使用一个简单的技术来避免这样做。

+3

通过说运行时行为(性能)有所不同,我认为它不是一种文体选择。仅仅因为在提问者的例子中,实际上没有区别,它是风格的。 – bmillare