“让”的功能替代

Log*_*ter 2 clojure

我发现自己以这种方式编写了很多 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语句是惯用的吗?

and*_*hut 5

let您描述的那种语句可能会让您想起命令式代码,但它们没有任何命令式。Haskell 也有类似的语句,用于将名称绑定到主体内的值。

  • 我认为它们有一些必要性,因为它们具有明确定义的操作顺序,而不是仅在需要时评估绑定名称。另一方面,它们确实是惯用的。 (3认同)