嵌套let的Clojure最佳实践

时间:2015-08-14 08:43:07

标签: clojure clojurescript

以下列方式使用Clojure嵌套let是一种好习惯,还是令人困惑?

(defn a-fun [config]
  (let [config (-> config (parse) (supply-defaults))]
  ;; do something with config
  ))

我注意到我在输入函数中经常解析/检查/验证事物的模式与外部世界交互(在这种情况下是暴露公共函数的Clojurescript库,但我也有同样感觉的Compojure路径) )。

是否令人困惑,因为必须了解绑定可见性的规则(不确定准确的措辞是什么)?

这样做的惯用方法是什么?将config名称更改为parsed-config,将其添加到其他功能中,完全不需要其他功能吗?

3 个答案:

答案 0 :(得分:8)

时,我会找到这个习语
  • 重新绑定是同样的事情和
  • 你想说明本地绑定取代了 全球性的。

例如

(defn fact [n]
  (loop [n n, answer 1]
    (if (pos? n)
      (recur (dec n) (* answer n))
      answer)))

这也会阻止你偶然使用全局绑定,因为我很容易这样做。

答案 1 :(得分:3)

@ Thumbnail的答案很好,但我个人几乎不会以这种方式影响内部绑定的外部绑定。即使您了解绑定规则,并且想要出于某个原因想要隐藏外部变量,对于阅读代码的人来说也会让人感到困惑 - 以后,在您忘记代码的工作原理之后,这很可能就是您。

假设我有一个复杂的函数,我看到变量foo在它的中间某处使用。我向上看并看到它的绑定 - 也许作为一个函数参数,这将是显而易见的。如果我没有注意到那个位置以下,那个名字就会反弹,那么我就会误解变量中的内容。

所以我通常会编写与代码中不同变量的作用相对应的新的相关名称。有时名称差异有些随意。

我认为这些是不影响变量的好理由,我认为@Thumbnail给出了继续前进的理由。有一些权衡,你必须决定什么是最适合你的情况。

短函数可能是更好的阴影上下文。就个人而言,如果我做了这样的事情,或者如果我一遍又一遍地这样做,我会添加一个非常明显的评论,可能是文件顶部附近的一个非常明显的评论。

编辑:正如nha的评论让我意识到的那样,当新绑定在前一个绑定之后立即发生时,影响变量会更合理;这让人很难错过这个名字被重新定义的事实。

答案 2 :(得分:1)

另一个选择是稍微重命名参数,保留" final"的总称。版本的数据:

(defn a-fun [config-in]
  (let [config (-> config-in (parse) (supply-defaults))]
  ;; do something with config
  ))

我有时会使用后缀-arg-orig等来区分各个处理阶段。