Clojure关闭效率?

Clojure关闭效率?,clojure,closures,lexical-closures,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 out

我经常交换!使用匿名函数的原子值,该函数在计算新值时使用一个或多个外部值。有两种方法可以做到这一点,一种是我所理解的闭包,另一种不是,我的问题是,哪种方法更好/更有效

下面是一个简单的虚构示例—向原子添加一个可变数值—显示了两种方法:

(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.韦伯的回答编辑以下内容(此内容太长,无法放入评论中):

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

我喜欢Clojure的一点是,虽然您可以用其他语言编写代码以更快地执行任何特定算法,但如果您编写习惯的Clojure代码,它将非常快,并且将是简单、优雅和可维护的。随着您试图解决的问题变得越来越复杂,简单性、优雅性和可维护性变得越来越重要。在我看来,Clojure是解决一系列复杂问题的最“有效”的工具

我的问题是,考虑到我有两种方法可以解决这个问题,那么更惯用的和Clojure风格的方法是什么?对我来说,当我问这个问题时,两种方法的“速度”是一个考虑因素。这不是最重要的一个,但我仍然认为这是一个合理的考虑,如果这是一个共同的模式,不同的方法是从其他角度洗。我认为A.韦伯下面的答案是,“哇!从杂草中拔出来!编译器可以很好地处理这两种方法,并且每种方法的相对效率都是未知的,而不必深入目标平台等的杂草。因此,请从语言名称中获取提示,如果这样做有意义,请使用闭包。”

于2014年4月10日结束编辑

我将把A.Webb的答案标记为已接受,尽管我真的接受了A.Webb的答案和omiel的答案——不幸的是,我不能同时接受这两个答案,加上我自己的答案,将它们汇总起来似乎有点无缘无故


我喜欢Clojure的一个特点是它有一个共同工作的社区。学习计算机语言不仅仅意味着学习代码语法——更重要的是,它意味着学习思考和理解问题的模式。Clojure及其背后的Lisp有一套功能强大的模式。对于r例如,同象性(“作为数据的代码”)这意味着您可以在编译时使用宏动态生成代码,或者通过分解结构,您可以简洁易懂地解压复杂的数据结构。这些模式都不是Clojure独有的,但Clojure将它们结合在一起,使解决问题成为一种乐趣。学习这些模式的唯一方法是向了解这些模式的人学习现在就开始使用它们。一年多前,当我第一次选择Clojure时,我之所以选择它而不是Scala和其他竞争者,其中一个原因是Clojure社区因其乐于助人和建设性而享有盛誉。我并没有失望——这次围绕我问题的交流,就像StackOverflow和其他网站上的许多其他交流一样,证明了这一点It’社区是多么愿意帮助像我这样的新手——谢谢!

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

你在杂草丛中太深了,回到主路


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

我更喜欢第一种方法,因为它更简单(只要闭包简单)读起来更容易一些。我经常在读一个匿名函数立即被参数调用的代码时遇到困难;我必须计算括号以确定发生了什么,我觉得这不是一件好事


我认为唯一可能是错误的做法是,如果闭包关闭在一个不应该被捕获的值上,比如长惰性序列的头部。

如果你想知道方法a是否比方法B更有效,请配置文件。显然,“效率”实际上指的是“开发人员效率”“,这是一个好问题。但是从运行时效率的角度来看,请注意在源代码中为
swap
(以及在许多类似的函数中),没有闭包的版本只是基于闭包的版本的一个方便的包装器:
(swap!a f x)
立即创建闭包并分派到
(swap!a#(f%x))
。这里的性能差异当然可以忽略不计。我开始回复的评论太长,无法放入评论框,因此我将其移动到问题的主体中