如何理解 clojure 中的 alt core.async

how to understand alt in clojure core.async

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

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

我还准备了以下link

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))

channel-op of [c t]表示通道c和值t:将值t放在通道c上。 ([val ch] (foo ch val)) 的结果表达式表示为操作出价 [val ch],但由于它是一个列表,[val ch] 应该作为一个函数求值,而 (foo ch val) 将是作为传递给 [val ch] 函数的参数。但是参数为 (foo ch val) 的 [val ch] 函数意味着什么?

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

在某些情况下,列表并不意味着 "evaluate as a function"。例如:

(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。表达式的其余部分被视为要在其中使用这些函数的 "body"。

but what does it mean for function of [val ch] with parameter of (foo ch val) ?

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

alt!/alt!!的解释:

我发现最容易想到 alt!alt!! 有点像 cond,除了不是测试条件来选择 body 来执行,它等待通道选择 body 来执行。每个子句由两部分组成,就像 cond – 第一部分("channel op")用于指定 alt! 应该等待的通道上,第二部分("result expr")指定如果该通道首先传递值应该发生什么。

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

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

…表示:

One of the channel operations that this call to alt! should block on is an attempt to take from either of two channels, c or t. If either of those send a value before any other channel op in this call to alt!, then execute (foo ch val) with val bound to the value taken from the channel that first delivered a value, and with ch bound to the channel that delivered val (which will be either c or t).

和下面的子句……

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

…表示:

One of the channel operations that this call to alt! should block on is an attempt to put input-val onto a channel called out. If that succeeds before any other channel op in this call to alt!, then execute (bar ch val) with val bound to input-val and ch bound to out (the channel that successfully received the value).

这两个子句加起来可以写成:

(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)))