以下列方式使用Clojure嵌套let
是一种好习惯,还是令人困惑?
(defn a-fun [config]
(let [config (-> config (parse) (supply-defaults))]
;; do something with config
))
我注意到我在输入函数中经常解析/检查/验证事物的模式与外部世界交互(在这种情况下是暴露公共函数的Clojurescript库,但我也有同样感觉的Compojure路径) )。
是否令人困惑,因为必须了解绑定可见性的规则(不确定准确的措辞是什么)?
这样做的惯用方法是什么?将config
名称更改为parsed-config
,将其添加到其他功能中,完全不需要其他功能吗?
答案 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
等来区分各个处理阶段。