Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Isn';t core.async与Clojure原则相反?_Clojure_Core.async - Fatal编程技术网

Isn';t core.async与Clojure原则相反?

Isn';t core.async与Clojure原则相反?,clojure,core.async,Clojure,Core.async,我看到许多Clojure程序员对新的core.async库充满热情,尽管它看起来很有趣,但我很难看到它如何符合Clojure原则,因此我有以下问题: 它在任何地方都使用可变状态,正如函数名中带有感叹号(如alt!)所示!,放!,等等。如果从通道中放置或获取值,则该通道将在原地修改。这难道不违背Clojure偏爱不可变数据结构、纯函数等的哲学吗?或者core.async是否仅用于无法避免可变的情况 由于“go”是一个宏(因此修改代码结构)并确保“第一个问题-是的,核心操作是副作用。但是通道没有通常

我看到许多Clojure程序员对新的core.async库充满热情,尽管它看起来很有趣,但我很难看到它如何符合Clojure原则,因此我有以下问题:

  • 它在任何地方都使用可变状态,正如函数名中带有感叹号(如alt!)所示!,放!,等等。如果从通道中放置或获取值,则该通道将在原地修改。这难道不违背Clojure偏爱不可变数据结构、纯函数等的哲学吗?或者core.async是否仅用于无法避免可变的情况

  • 由于“go”是一个宏(因此修改代码结构)并确保“第一个问题-是的,核心操作是副作用。但是通道没有通常与可变引用相关的问题,因为它们不代表“位置”“-通道是不透明的,您无法检查它们,事实上,您甚至无法在读取nil之后查询通道是否关闭

    第二个问题——做任何比浅收益率更重要的事情都意味着整个程序的转换。这是一个权衡,我认为是合理的。构图的层次是通道而不是块,它们构图很好

    最后一个问题是,您可以轻松地通过通道执行Rx样式的映射/过滤/减少操作,人们已经这样做了

  • 另一方面,Core.async只能在不变性为标准的系统中使用。因此Clojure的原则支持core.async,而不是相反

  • 这是一个限制,也发生在clojure的其他地方,不使用
    %
    符号组合的匿名函数的限制似乎至少体现了相同的想法。当然,并不是说找到另一个限制的案例会让它变得更好

  • 我自己还没有看到过这种情况,不过如果你试图用一种简单、干净的方式表达代码,然后用一种。。。不是那样的


  • Rich Hickey在blip.tv的一次讲座中说Clojure“85%的功能性”。我喜欢将core.async作为其他15%的一部分。Core.async非常适合于通过承诺、延迟和其他事情进行可靠的用户交互,这些事情可能会以更混乱的方式进行。

    go宏(其局部性)的限制也是一个特性:它强制执行有状态操作的源代码局部性。

    也许是使用
    (外部go宏可通过宏及其宏扩展时间完成:

    这是我的例子:

    (ns fourclojure.asynco
          (require [clojure.core.async :as async :refer :all]))
    
    (defmacro runtime--fn [the-fn the-value]
      `(~the-fn ~the-value)
      )
    (defmacro call-fn [ the-fn]
      `(runtime--fn ~the-fn (<! my-chan))
      )
    
    (def my-chan (chan))
    
    (defn  read-channel [the-fn]
      (go
      (loop []
        (call-fn the-fn)
        (recur)
        )
      ))
    
    (defn paint []
      (put! my-chan "paint!")
      )
    

    我在嵌套的go中尝试过这个解决方案,并且也能工作。但是我不确定它是否是一个正确的路径

    每个程序都有两个部分,一个部分始终是非函数的,将数据输入、输出等等。对于这一部分,我们知道有core.async,core.async确实有可变的东西,但请注意两件事。通道的状态基本上是由库管理的。你放在它上面的东西是什么,可以称之为flowstate。这意味着当你放像频道这样的东西时,你不希望再看到它,甚至改变它

    Core.async很适合管理程序的这一部分。对于其余部分,即对数据的所有转换和计算,clojure尽其所能为您提供良好的工具,从功能上实现这一点

    在我看来,这妨碍了简单性和可组合性。为什么 这不是问题吗

    有两个世界,同步世界和异步世界。你可以用put!和take!放置东西,或者从异步世界中取出东西,但除此之外(可能还有其他函数)这些到世界是相互分离的。Clojure不想成为一种完全异步的语言。函数和数据转换是需要可组合的

    可能是前两个问题的结果,很多代码 core.async使用较低级别的构造,例如循环/重现,而不是 映射/过滤/减少。这不是倒退吗

    通过通道进行类似的操作是可能的。Core.async还很年轻,并且还没有编写所有可能的构造和函数

    但通常情况下,如果您有大型数据转换,您并不真的希望在异步世界中进行转换,您希望将它们放在一个集合中,然后抛出类似reducers框架的东西

    要理解的主要问题是,core.async不是新标准,它只是帮助您编程的另一件事。有时您需要STM,有时需要代理,有时需要CSP,这取决于它,clojure希望为您提供所有选项


    人们喜欢core.async的一个原因是,它有助于处理一些本来很难处理的事情,比如处理回调。

    你的第一点忽略了Clojure在引用和值之间的区别。你不会在core.async中改变值。我认为他(她)是关键是,虽然Clojure中存在可变函数,但它们不应该被普遍使用,而是作为一个逃生舱口,以备您真正需要。@vemv True,您不会改变输入通道中的值。但您会改变通道本身的状态。这与原子、引用、代理等一致。表示更改随着时间的推移e是一个核心Clojure命题。关于我的第三个问题,Rich Hickey似乎刚刚在core.async中创建了许多新的高级函数,包括通道的map、filter和reduce。请参见他昨天发布的内容:有趣的一点。它确实很容易发现通道突变,因为我们不必查看o的定义go块中调用了其他函数。从这个角度来看,这是一个优势,而其他一些答案表明这是一个可以容忍的劣势。您好,cgrand,我发布了一个可能的解决方案,以避免go宏的限制,您认为这是一个实用的解决方案吗
    (ns fourclojure.asynco
          (require [clojure.core.async :as async :refer :all]))
    
    (defmacro runtime--fn [the-fn the-value]
      `(~the-fn ~the-value)
      )
    (defmacro call-fn [ the-fn]
      `(runtime--fn ~the-fn (<! my-chan))
      )
    
    (def my-chan (chan))
    
    (defn  read-channel [the-fn]
      (go
      (loop []
        (call-fn the-fn)
        (recur)
        )
      ))
    
    (defn paint []
      (put! my-chan "paint!")
      )
    
    (read-channel print)
    (repeatedly 50 paint)