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