是不是core.async违背Clojure的原则?
我已经看到许多Clojure程序员对新的core.async库充满热情,虽然看起来很有趣,但我很难看出它是如何符合Clojure原则的,所以我有这样的问题:
- 它在任何地方都使用可变状态,因为函数名称带有感叹号,比如alt !, put !,> !,等等。 如果你从某个频道input或取得一个值,则该频道将被修改。 Clojure更喜欢不可变的数据结构,纯函数等等,这不是违背了吗? 还是core.async只能用在可变的东西根本无法避免的地方?
-
由于“go”是一个macros(因此修改代码结构)并确保“<!” 直接用在一个转换块中,不可能使用“<!” 在另一个函数里面,像这样:
(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。 这不是一个倒退吗?
我错在哪里?
提前致谢。
首先关注的是 – 核心业务是副作用。 然而,频道没有通常与可变引用相关的问题,因为它们不代表“地点” – 频道是不透明的,你不能检查它们,事实上你甚至不能查询频道是否closures,零。
第二个问题 – 做比浅收益更多的事情就意味着整个项目的转型。 这是一个折衷,我认为是一个合理的。 组成的水平是渠道不去块,他们组成就好了。
最后的担心,你可以轻松地做Rx风格的地图/过滤/减less操作的渠道和人已经这样做了。
gomacros(其局部性)的限制也是一个特征:它强制执行有状态操作的源代码局部性。
-
这是相反的, Core.async只能用于不可变性是常态的系统 。 所以Clojure的原则使core.async而不是相反。
-
这是一个限制,也发生在clojure的其他地方,匿名函数与
%
符号的组合限制似乎至less呈现相同的想法。 不是说find另一个限制的情况,当然会更好。 -
我还没有看到我的自我,尽pipe如果你试图采用简单的代码,以一种方式expression,然后用一种方式来expression,那么这将是一个倒退。 。
Rich Hickey在其中一次blip.tv讲座中说Clojure是“85%function”的。 我喜欢看到core.async作为其他15%的一部分。 Core.async非常适合用户之间的交互,而这些交互是通过承诺,延迟和其他方式完成的,可能会以更加混乱的方式进行。
每个程序都有两部分,一部分是非function性的数据input,吐出等等。 对于这部分我们知道有core.async,core.async是可变的东西,但注意两点。 渠道的状况基本上由图书馆pipe理。 你放在上面的东西是什么,可能会叫flowstate。 也就是说,当你放置一个像频道的东西时,你不会期望回到它,甚至改变它。
Core.async很好地pipe理你的程序的这一部分。 对于其他所有的数据转换和计算,clojure会尽最大努力为您提供function强大的工具。
在我看来,这阻止了简单性和可组合性。 为什么这不是问题?
有两个世界,同步和asynchronous世界。 你可以放东西,或者把异样的东西拿出来放! 拿! 但是除此之外(还有其他一些function)这些世界是彼此分离的。 Clojure不想成为完全asynchronous的语言。 函数和数据转换是需要组合的。
也许作为前两个问题的结果,core.async的许多代码使用较低级别的构造,如loop / recur,而不是map / filter / reduce。 是不是倒退了一步?
像这样的频道操作将是可能的。 Core.async还很年轻,而且还没有写出所有可能的结构和function。
但是一般情况下,如果你有大数据转换,你不想在asynchronous世界中做这些转换,你想让它们在一个集合中,然后在它上面扔一些像reducres框架的东西。
要理解的主要是这个,core.async不是新的标准,它只是帮助你编程的一件事。 有时你需要STM,有时代理商,有时CSP它依赖和clojure想给你所有的select。
人们喜欢core.async的一个原因是因为它有助于处理一些难以处理的东西,比如处理callback。
也许一个可能的解决scheme使用(<! c)
外部去macros可以使用macros和其macros展开时间:
这是我的例子:
(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!") )
并testing它:
(read-channel print) (repeatedly 50 paint)
我已经试过这个解决scheme嵌套去也可以。 但我不确定这是否是一条正确的道路