core.async能否使用序列实现其函数?

8
Rich Hickey在Strange Loop的传输器演示中告诉我们,Clojure 1.6中有两个map的实现,一个是在clojure.core中用于序列,另一个是在core.async中用于通道。

enter image description here

现在我们知道,在1.7中,有传输器,当给定函数而不是集合时,像mapfilter这样的高阶函数返回一个foldrreduce)函数。

我试图表达并失败了,就是为什么core.async函数不能返回序列或类似于Seq。我感觉'接口'(协议)是不同的,但我看不出来。

如果你从通道中取出第一项,那么肯定可以表示为从序列中取出第一项,难道不是吗?

我的问题是:core.async可以根据序列实现其函数吗?

2个回答

10

是的,在某种意义上,它们可能是可以的。如果您忽略go blocks(暂时这样做),那么以下内容并没有什么问题:

(defn chan-seq [ch]
  (when-some [v (<!! c)]
    (cons v (lazy-seq (chan-seq ch)))))

但是请注意这里的<!!调用。这被称为"阻塞获取":在这个函数内部有一些承诺和锁定,会导致当前执行的线程停止,直到通道上有一个值可用。所以如果你不介意让Java线程坐在那里什么都不做,那么这个方法可以正常工作。
go block的想法是使逻辑过程更加廉价;为了实现这一点,go block将块的主体重写为附加到通道的一系列回调函数,因此在go block中对<!的调用会变成像这样的东西: (take! c k),其中k是回调函数,用于处理go block的其余部分。
现在,如果我们拥有真正的continuations,或者JVM支持轻量级线程,那么是的,我们可以组合go-blocks和阻塞获取。但是,这目前涉及到深层字节码重写(就像Pulsar/Quasar项目所做的那样)或一些非标准JVM功能。在创建core.async时,这两个选项都被排除了,而选择了更简单的本地go block转换,希望能更容易实现(并且希望能更容易理解)。

1
稍作调整,使第一项的获取也变为惰性。
(defn chan-seq [ch]
  (lazy-seq
   (if-some [v (<!! ch)]
     (cons v (chan-seq ch))
     nil)))

> Blockquote


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接