【问题标题】:how to understand alt in clojure core.async如何理解 clojure core.async 中的 alt
【发布时间】:2016-01-18 13:44:14
【问题描述】:

我已阅读以下文档和示例,但仍然不明白它的真正含义。我了解 alts !!,但不是 alt !!。有人举一个容易理解的例子吗?

https://clojure.github.io/core.async/#clojure.core.async/alt!!

我也准备好了以下链接

In Clojure (core.async) what's the difference between alts and alt?

更新:文档中的示例是:

(alt!
  [c t] ([val ch] (foo ch val))
  x ([v] v)
  [[out val]] :wrote
  :default 42)

为第二行

[c t] ([val ch] (foo ch val))

[c t] 的channel-op 表示一个通道c 和一个值t:将值t 放在通道c 上。 ([val ch] (foo ch val)) 的 result-expr 表示为操作出价 [val ch],但由于它是一个列表,因此 [val ch] 应该作为一个函数计算,并且 (foo ch val) 将是作为传递给[val ch]函数的参数。但是对于参数为 (foo ch val) 的 [val ch] 函数意味着什么?

【问题讨论】:

  • 哪部分不明白?
  • 我认为您对第二行的解释有些偏离。 [c t] 是一个端口向量。 [val ch] 是一个绑定(如你所说)。 ch 是可以从中获取的频道; val 是取值。然后使用该绑定评估函数foo。请参阅gist.github.com/konacaret/d1f5c19cfbe46d3b97a3 了解一个简单的示例。
  • 这个例子非常多,非常清楚。最好把它放在官方文档上:)

标签: clojure core.async


【解决方案1】:

[c t] ([val ch] (foo ch val))

在某些情况下,列表并不意味着“评估为函数”。例如:

(ns com.foo.bar
  (:require …))

在上面的代码中,没有调用名为:require 的函数。

另一个用于函数应用程序以外的列表的示例是letfn

(letfn [(foo [x] (+ (bar 1) x))
        (bar [x] (+ 2 x))]
  (+ (foo 5) (bar 7)))

如上所见,letfn 有两个列表,一个以符号foo 开头,一个以符号bar 开头,而这两个列表都不是传统的函数调用。相反,letfn定义两个新函数,一个名为 foo,另一个名为 bar。表达式的其余部分被视为使用这些函数的“主体”。

但是对于参数为 (foo ch val) 的 [val ch] 函数意味着什么?

类似于letfnalt定义一个名为val的值和一个名为ch的通道,然后表达式的其余部分((foo ch val))被视为使用这两个名称的“body”。

alt!/alt!!的解释:

我发现最容易将alt!alt!! 视为有点像cond,除了不是测试条件来选择要执行的主体,而是等待通道来选择要执行的主体。每个子句由两部分组成,就像 cond - 第一部分(“channel op”)用于指定 alt! 应该等待的频道,第二部分( "result expr") 指定如果该通道首先传递一个值会发生什么。

由于您可能希望在发生这种情况时访问通道传递的值通道本身,因此 result expr 为您提供了绑定值和符号的通道,以及使用这些绑定执行的代码体。因此,下面的子句……

[c t]
([val ch]
  (foo ch val))

……意思是:

此对alt! 的调用应阻止的通道操作之一是尝试从ct 两个通道中的一个获取。如果其中任何一个在此调用中的任何其他 channel op 之前发送值到 alt!,则执行 (foo ch val) 并将 val 绑定到从第一次传递值的通道中获取的值,并将ch 绑定到传递val 的通道(将是ct)。

还有下面的子句……

[[out input-val]]
([val ch]
  (bar ch val))

……意思是:

这个对alt! 的调用应该阻塞的通道操作之一是尝试 input-val 放到一个名为out 的通道上。如果在调用alt! 中的任何其他通道操作 之前成功,则执行(bar ch val)val 绑定到input-valch 绑定到out(通道成功接收到值)。

总之,这两个子句可以写成:

(alt!
  [c t]        ; "Takes" can be a single channel instead of vectors.
  ([val ch]
    (foo ch val))

  [[out input-val]] ; "Puts" must be nested vectors.
  ([val ch]
    (bar ch val)))

【讨论】:

  • 感谢 erikprice,很好的解释。 [c t]的一个问题,c和t频道都像konacaret showgist.github.com/konacaret/d1f5c19cfbe46d3b97a3吗?我再次阅读了文档,如果它是 [[c t]],那么 c 是 put 通道,t 是要放置的值。如果只是 [c t],那么两者都应该是频道,对吗?
  • @DanielWu 是的,你是对的。我误将向量表示为“放置”操作,但“放置”需要嵌套向量,正如您所描述的那样,非嵌套向量只是从中“获取”的多个通道。我已经更新了答案以反映更正,以便它通过“takes”和“puts”显示。
猜你喜欢
  • 2014-03-31
  • 2015-07-04
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 2018-08-27
  • 2016-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多