core.async 是不是已经按照序列实现了它的功能?

问题描述 投票:0回答:2

Rich Hickey 的 Strange Loop transducer presentation 告诉我们在 Clojure 1.6 中有两种

map
的实现,一种用于
clojure.core
中的序列,一种用于
core.async
中的通道。

enter image description here

现在我们知道在 1.7 中我们有换能器,当给定一个函数而不是一个集合时,从高阶函数如

foldr
reduce
返回一个
map
(
filter
) 函数。

我试图阐明和失败的是为什么

core.async
函数不能返回序列,或者像
Seq
一样。我觉得“接口”(协议)不同,但我看不出如何。

当然,如果您要从频道中取出第一项,那么您可以将其表示为从序列中取出第一项吗?

我的问题是:

core.async
是否已经按照序列实现了它的功能?

clojure sequence core.async transducer
2个回答
9
投票

是的,从某种意义上说,他们本来可以。如果你忽略 go 块(暂时让我们这样做),那么像下面这样的东西真的没有错:

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

但是请注意这里的

<!!
电话。这称为“take blocking”:此函数内部有一些 promises 和锁,它们将导致当前正在执行的线程暂停,直到通道上的值可用为止。因此,如果您不介意让 Java 线程坐在那里什么也不做,那么这会很好地工作。

go blocks背后的想法是让逻辑过程更便宜;为了实现这一点,go 块将块的主体重写为一系列附加到通道的回调,以便在内部对 go 块内的

<!
的调用变成这样的东西
(take! c k)
其中
k 
是对 go 块其余部分的回调。

现在如果我们有真正的延续,或者如果 JVM 支持轻量级线程,那么是的,我们可以结合 go-blocks 和阻塞 takes。但这目前涉及深度字节码重写(就像 Pulsar/Quasar 项目所做的那样)或一些非标准的 JVM 功能。在创建 core.async 时排除了这两个选项,取而代之的是更易于实现(并且希望更易于推理)的本地 go 块转换。


0
投票

稍微调整一下,使第一个项目的拍摄也变得懒惰。

(defn chan-seq [ch]
  (lazy-seq
   (if-some [v (<!! ch)]
     (cons v (chan-seq ch))
     nil)))

> Blockquote

© www.soinside.com 2019 - 2024. All rights reserved.