如何理解Clojure core.async中的alt?

5
我已阅读以下文档和示例,但仍不理解它的真正含义。我理解alts!!,但不理解alt!!。有人能提供一个易于理解的示例吗?

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

我也已经阅读了以下链接:

在Clojure(core.async)中,alts和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 [c t] 的意思是将值 t 放在通道 c 上。 result-expr ([val ch] (foo ch val)) 的意思是为该操作出价 [val ch],但由于它是一个列表,[val ch] 应被视为一个函数进行评估,并且 (foo ch val) 将作为参数传递给 [val ch] 的函数。但是对于带有参数 (foo ch val) 的 [val ch] 函数意味着什么?


你不理解哪个部分? - Leon Grapenthin
我认为你对第二行的解释有些偏差。[c t]是一个端口向量。[val ch]是一个绑定(正如你所说)。ch是可以从中获取的通道;而val是取出的值。然后使用该绑定来评估函数foo。请参见https://gist.github.com/konacaret/d1f5c19cfbe46d3b97a3,了解此简单示例。 - konacaret
非常感谢提供的示例,非常清晰易懂。最好将其放在官方文档中 :) - Daniel Wu
1个回答

10

[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。表达式的其余部分被视为“主体”,在其中使用这些函数。
letfn类似,alt定义了一个名为val的值和一个名为ch的通道,然后剩余的表达式((foo ch val))被视为“主体”,在其中使用这两个名称。 < h1 > alt!/ alt!!的解释:

我觉得最容易将alt!alt!!视为类似于cond,只不过它不是测试条件来选择要执行的主体,而是等待通道来选择要执行的主体。每个子句由两个部分组成,就像cond一样-第一部分(“通道操作”)用于指定alt!应等待的通道,第二部分(“结果表达式”)指定如果该通道首先传递一个值应该发生什么。

因为您可能希望在发生这种情况时访问通道传递的值或通道本身,所以结果表达式让您有机会将值和通道绑定到符号,并执行具有这些绑定的代码主体。因此,以下子句...

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

…的意思是:

这个调用 alt! 的通道操作之一应该阻塞在尝试从两个通道 ct获取 值的过程中。如果其中任何一个在这个调用 alt! 中的任何其他通道操作之前发送了一个值,那么使用从首先传递值的通道获取的值将执行 (foo ch val),并将 val绑定到传递val的通道(它将是ct中的一个),将ch绑定到传递val的通道。

以下是需要翻译的子句...

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

...的意思是:

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

总的来说,这两个子句将被写成:

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

1
谢谢erikprice,解释得非常好。关于[c t]的一个问题,c和t都像konacaret展示的那样是通道吗?我再次阅读了文档,如果是[[c t]],那么c是放置通道,t是要放置的值。如果只是[c t],那么两者都应该是通道,我是对的吗? - Daniel Wu
@DanielWu 是的,你说得对。我误将向量表示为“put”操作,但是“put”需要像你描述的嵌套向量,而非嵌套向量只是多个通道可以从中“take”。我已更新答案以反映更正,以便显示“takes”和“puts”。 - erikprice

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