我发现自己以这种方式编写了很多 clojure:
(defn my-fun [input]
(let [result1 (some-complicated-procedure input)
result2 (some-other-procedure result1)]
(do-something-with-results result1 result2)))
Run Code Online (Sandbox Code Playgroud)
这let句话似乎非常……势在必行。我不喜欢的。原则上,我可以像这样编写相同的函数:
(defn my-fun [input]
(do-something-with-results (some-complicated-procedure input)
(some-other-procedure (some-complicated-procedure input)))))
Run Code Online (Sandbox Code Playgroud)
问题在于它涉及重新计算 some-complicated-procedure,这可能非常昂贵。您也可以想象这some-complicated-procedure实际上是一系列嵌套的函数调用,然后我要么必须编写一个全新的函数,要么冒着第一次调用中的更改不会应用于第二次调用的风险:
例如,这有效,但我必须有一个额外的浅层顶级函数,这使得很难进行心理堆栈跟踪:
(defn some-complicated-procedure [input] (lots (of (nested (operations input)))))
(defn my-fun [input]
(do-something-with-results (some-complicated-procedure input)
(some-other-procedure (some-complicated-procedure input)))))
Run Code Online (Sandbox Code Playgroud)
例如,这很危险,因为重构很难:
(defn my-fun [input]
(do-something-with-results (lots (of (nested (operations (mistake input))))) ; oops made a change here that wasn't applied to the other nested calls
(some-other-procedure (lots (of (nested (operations input))))))))
Run Code Online (Sandbox Code Playgroud)
考虑到这些权衡,我觉得除了编写冗长的命令式let语句之外,我别无选择,但是当我这样做时,我无法摆脱我不是在编写惯用的 clojure 的感觉。有没有办法解决上面提出的计算和代码清洁问题并编写惯用的 clojure?命令式let语句是惯用的吗?
let您描述的那种语句可能会让您想起命令式代码,但它们没有任何命令式。Haskell 也有类似的语句,用于将名称绑定到主体内的值。