首页 文章

是不是与Clojure原则相反的core.async?

提问于
浏览
42

我见过很多Clojure程序员热衷于新的core.async库,虽然看起来非常有趣,但我很难看到它是如何符合Clojure原则的,所以我有这些问题:

  • 它在任何地方都使用可变状态,因为函数名称通过带有感叹号来表示,例如alt!,put!,>!和其他 . 如果您从 Channels 中输入或获取值,则会在该位置修改该 Channels . 是否与Clojure哲学相反,它更倾向于使用不可变数据结构,纯函数等等?或者是core.async仅在无法避免可变事物的情况下使用?

  • 因为“go”是一个宏(从而修改代码结构)并确保“<!”直接在go-block中使用,不能使用“<!”在另一个函数里面,像这样:

(defn take-and-print [c]
 (println (<! c)))

(def ch (chan 1))
(>!! ch 123)

(go (take-and-print ch))

Assert failed: <! used not in (go ...) block

在我看来,这可以防止简单性和可组合性 . 为什么不是问题?

  • 也许由于前两个问题,core.async的许多代码使用较低级别的构造,例如loop / recur而不是map / filter / reduce . 这不是倒退吗?

我在哪里错过了这一点?

提前致谢 .

6 回答

  • 5

    Rich Hickey在其中一个blip.tv讲座中表示,Clojure的功能是“85%” . 我喜欢将core.async视为其他15%的一部分 . Core.async非常适合用户之间的互动,这些事情本来可以通过承诺,延迟和其他事情来完成,可能会以更混乱的方式进行 .

  • -1

    第一个问题 - 是核心操作是副作用 . 但是通道没有通常与可变引用相关的问题,因为它们不代表“地方” - 通道是不透明的,你无法检查它们,实际上你甚至无法查询通道是否关闭或超出阅读范围零 .

    第二个问题 - 做任何不仅仅是浅层产量将意味着整个项目的转型 . 这是一个权衡,我认为是合理的 . 组成的水平是通道而不是块,它们组成很好 .

    最后的关注点,你可以很容易地做Rx风格的 Map /过滤/减少操作的渠道和人已经这样做了 .

  • 1

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

  • 37
    • 它有点相反, Core.async can only be used in systems where Immutability is the norm . 所以Clojure的原则启用了core.async而不是反向 .

    • 这是一个限制,也发生在clojure的其他地方,匿名函数的限制与 % 符号组成似乎至少表现出相同的想法 . 并非找到另一个限制的情况当然会更好 .

    • 我没有看到这是我的自我,尽管如果你试图采用简单的代码并且在以一种方式表达时清洁然后以某种方式表达它,那么这将是向后退一步 . ..

  • 10

    每个程序都有两个部分,一部分始终是非函数通话数据,吐出来等等 . 对于这部分我们知道有core.async,核心.async确实有可变的东西,但请注意两件事 . 渠道的状态基本上由图书馆管理 . 你放在它上面的东西是什么,可能称之为flowstate . 这意味着,当您放置类似通道的东西时,您不希望再回到它,甚至更改它 .

    Core.async非常适合管理这部分程序 . 对于其余的,对数据的所有转换和计算,clojure会尽力为您提供良好的工具来实现它 .

    在我看来,这会妨碍简单性和可组合性 . 为什么不是问题?

    有两个世界,同步和异步世界 . 你可以把东西放进去,或者用put来取出异步的东西!并采取!但除此之外(也许还有一些其他功能)这些对世界来说是彼此分开的 . Clojure不想成为完全异步的语言 . 功能和数据转换是需要组合的 .

    也许作为前两个问题的结果,core.async的很多代码使用较低级别的构造,例如loop / recur而不是map / filter / reduce . 这不是一个倒退

    可以通过 Channels 进行操作 . Core.async仍然很年轻,并没有编写所有可能的构造和函数 .

    但一般来说,如果你有大数据转换,你真的不想在异步世界中做它们,你想要将它们放在一个集合中,然后在它上面添加类似reducres框架的东西 .

    要理解的主要内容是,core.async不是新标准,它只是帮助您编程的另一件事 . 有时候你需要STM,有时需要代理,有时候它需要CSP,而clojure想要给你所有的选择 .

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

  • 16

    也许一个可能的解决方案使用 (<! c) 外部去宏可以用宏和它的宏扩展时间来完成:

    这是我的例子:

    (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)
    

    我已经在嵌套go中试过这个解决方案并且也可以工作 . 但我不确定它是不是一条正确的道路

相关问题