Clojure的关闭效率?

Chr*_*ant 5 closures clojure lexical-closures

我经常交换!使用匿名函数的原子值,该匿名函数在计算新值时使用一个或多个外部值。有两种方法可以执行此操作,一种是我了解的是闭合,而另一种则不是,我的问题是哪种方法更好/更有效?

这是一个简单的示例-向原子添加变量数值-显示两种方法:

(def my-atom (atom 0))

(defn add-val-with-closure [n]
  (swap! my-atom 
         (fn [curr-val] 
           ;; we pull 'n' from outside the scope of the function
           ;; asking the compiler to do some magic to make this work
           (+ curr-val n)) ))

(defn add-val-no-closure [n]
  (swap! my-atom 
         (fn [curr-val val-to-add] 
           ;; we bring 'n' into the scope of the function as the second function parameter
           ;; so no closure is needed
           (+ curr-val val-to-add))
         n))
Run Code Online (Sandbox Code Playgroud)

这是一个虚构的示例,当然,您实际上不会编写此代码来解决此特定问题,因为:

(swap! my-atom + n)
Run Code Online (Sandbox Code Playgroud)

无需额外功能即可完成相同的操作。

但是在更复杂的情况下,您确实需要一个函数,然后问题就出现了。对我来说,从编码的角度来看,解决问题的两种方法的复杂度大致相同。如果是这样,我应该选择哪个?我的工作假设是,非封闭方法是更好的方法(因为编译器更容易实现)。

解决问题的第三种方法是不使用匿名函数。如果使用单独的命名函数,则不能使用闭包,也不会出现问题。但是内联匿名函数通常会使代码更具可读性,我想将这种模式留在我的工具箱中。

谢谢!

编辑以下内容以回答A. Webb的回答(此时间太长,无法发表评论):

我在问题中使用“效率”一词是一种误导。更好的词可能是“优雅”或“简单”。

我喜欢Clojure的一件事是,虽然您可以编写代码以使用其他语言更快地执行任何特定的算法,但是如果您编写惯用的Clojure代码,它的运行速度将相当快,而且它将变得简单,优雅且可维护。 。随着您要解决的问题变得越来越复杂,简单性,优雅性和可维护性变得越来越重要。从这个意义上讲,IMO,Clojure是解决各种复杂问题的最“有效”的工具。

我的问题确实是-考虑到有两种方法可以解决此问题,请问有什么更惯用的和Clojure风格的方法呢?对我来说,当我问这个问题时,两种方法的“快速”程度是一个考虑因素。这不是最重要的一种,但是我仍然认为,如果这是一种常见的模式,并且从其他角度来看是不同的方法,那是一个合理的考虑。我认为A. Webb在下面的回答是:“哇!从杂草中撤出!编译器将很好地处理这两种方法,并且无论如何,每种方法的相对效率都是未知的,而不必深入了解目标平台之类的杂草。因此,请从语言名称中获取提示,并在有意义时使用闭包。”

2014年4月10日截止编辑

我将A.Webb的答案标记为已接受,尽管我确实接受A.Webb的答案和omiel的答案-不幸的是,我不能同时接受它们,并且添加自己的答案将它们汇总起来似乎有点免费的。

我喜欢Clojure的众多优点之一是一起工作的社区。学习计算机语言不仅意味着学习代码语法,更重要的是,它还意味着学习思考和理解问题的模式。Clojure及其背后的Lisp具有如此强大的模式集。例如,同音(“代码作为数据”)意味着您可以在编译时使用宏动态生成代码,或者通过解构使您可以简洁明了地解压缩复杂的数据结构。Clojure并不是所有模式都不是唯一的,但是Clojure可以通过使解决问题感到高​​兴的方式将它们组合在一起。学习这些模式的唯一方法是从已经知道和使用它们的人们那里学习。当我一年多前第一次选择Clojure时,我之所以选择Scala和其他竞争者,原因之一是Clojure社区的帮助和建设性声誉。而且我也没有失望-围绕我的问题进行的这种交流,就像StackOverflow和其他地方的许多其他交流一样,表明了社区如何愿意帮助像我这样的新来者-谢谢!

A. *_*ebb 2

在弄清楚当前目标主机当前版本的当前编译器版本的实现细节后,您将不得不开始担心优化器和 JIT,然后是目标计算机的处理器。

你在杂草丛中太深了,请返回主路。

在适用时关闭自由变量是很自然的事情,也是一个极其重要的习惯用法。您可能会假设一种名为 Clojure 的语言对闭包具有良好的支持。