8

Rich Hickey 的 Strange Loop 转换器演示文稿告诉我们 Clojure 1.6 中有两种实现map,一种用于序列输入clojure.core,一种用于通道输入core.async

在此处输入图像描述

现在我们知道,在 1.7 中我们有转换器,对于这些转换器,foldr( reduce) 函数是从高阶函数返回的,例如mapfilter当给定一个函数而不是一个集合时。

我试图表达和失败的是为什么core.async函数不能返回一个序列,或者是Seq-like。我有一种“接口”(协议)不同的感觉,但我不知道如何。

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

我的问题是:可以core.async在序列方面实现它的功能吗?

4

1 回答 1

9

是的,从某种意义上说,他们本来可以。如果您忽略 go 块(暂时让我们这样做),那么以下内容确实没有错:

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

但请注意这里的<!!调用。这称为“获取阻塞”:在此函数内部有一些承诺和锁,它们将导致当前正在执行的线程暂停,直到通道上的值可用。因此,如果您不介意让 Java 线程坐在那里什么都不做,那么这会很好。

go blocks 背后的想法是使逻辑过程更便宜。为了实现这一点,go 块将块的主体重写为附加到通道的一系列回调,以便在内部<!对 go 块内部的调用变成类似这样的东西(take! c k),其中k是对其余部分的回调去块。

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

于 2014-10-30T15:21:24.160 回答