Clojure关闭效率?

时间:2014-03-08 10:18:08

标签: clojure closures 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))

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

(swap! my-atom + n)

做同样的事情而不需要额外的功能。

但在更复杂的情况下,你确实需要一个功能,然后出现问题。对我来说,解决问题的两种方法从编码角度来看具有相同的复杂性。如果是这样的话,我应该更喜欢哪一个?我的工作假设是非闭包方法更好(因为编译器实现起来更简单)。

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

谢谢!

编辑以回应A. Webb在下面的回答(这太长了,无法发表评论):

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

我喜欢Clojure的一件事是,虽然你可以编写代码以便在其他语言中更快地执行任何特定的算法,但如果你编写惯用的Clojure代码,它会变得非常快,而且它会变得简单,优雅,并且可维护。由于您要解决的问题变得更加复杂,简单性,优雅性和可维护性变得越来越重要。 IMO,Clojure是解决一系列复杂问题的最有效“工具”。

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

2014年4月10日结束编辑

我打算将A.韦伯的答案标记为已被接受,虽然我真的接受A.韦伯的回答和omiel的回答 - 不幸的是我不能接受他们两个,并且添加我自己的回答卷起来似乎只是有点无偿。

我喜欢Clojure的众多事情之一就是与之合作的人群。学习计算机语言并不仅仅意味着学习代码语法 - 更重要的是它意味着学习思考和理解问题的模式。 Clojure和Lisp背后有一套非常强大的模式。例如,homoiconicity(“代码作为数据”)意味着您可以使用宏在编译时动态生成代码,或者解构允许您简洁且可读地解包复杂的数据结构。没有一种模式是Clojure独有的,但Clojure将它们聚集在一起,使解决问题成为一种乐趣。学习这些模式的唯一方法是来自已经知道并使用它们的人。当我在一年多前第一次选择Clojure时,我选择Scala和其他竞争者的原因之一就是Clojure社区的声誉,因为它有助于建设性。而且我并没有感到失望 - 围绕我的问题进行这种交流,就像StackOverflow和其他地方的许多其他人一样,表明社区有多么愿意帮助像我这样的新人 - 谢谢!

2 个答案:

答案 0 :(得分:2)

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

你的杂草太深了,转回主路。

在适用时关闭自由变量是很自然的事情,也是一个非常重要的习惯用语。你可以假设一个名为Clojure的语言对闭包有很好的支持。

答案 1 :(得分:1)

我更喜欢第一种方法更简单(只要闭包很简单)并且更容易阅读。我经常很难阅读代码,你会立即使用参数调用匿名函数;我必须决定计算括号,以确定发生了什么,我觉得这不是一件好事。

我认为唯一可能做错事的方法是,如果闭包关闭了一个不应该被捕获的值,就像一个长懒惰序列的头部。