Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to understand alt in clojure core.async

I have read the following document and the example, but still doesn't get what it really means. I understand alts!!, but not alt!!.Anybody show an example easy to understand?

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

I have also ready the following link

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

update: The example is in the doc is:

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

for the second line of

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

channel-op of [c t] means a channel c and an value t: put value t on channel c. result-expr of ([val ch] (foo ch val)) means bidding [val ch] for the operation, but since it's a list, [val ch] should be evaluate as a function, and (foo ch val) will be as the parameter passed to function of [val ch]. but what does it mean for function of [val ch] with parameter of (foo ch val) ?

like image 568
Daniel Wu Avatar asked Jan 07 '23 19:01

Daniel Wu


1 Answers

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

There are some cases where a list doesn't mean "evaluate as a function". For example:

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

In the above code, there is no function called :require being called.

Another example of lists being used for something other than function application is letfn:

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

As you can see above, letfn has two lists, one starting with the symbol foo, and one starting with the symbol bar, and neither of these lists is a traditional function call. Instead, letfn is defining two new functions, one with the name foo, and the other with the name bar. The rest of the expression is treated as a "body" in which to use those functions.

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

Similar to letfn, alt defines a value named val and a channel named ch, and then the rest of the expression ((foo ch val)) is treated as a "body" in which to use those two names.

Explanation of alt!/alt!!:

I find it easiest to think of alt! and alt!! as being somewhat like cond, except instead of testing conditions to choose a body to execute, it waits on channels to choose a body to execute. Each clause consists of two parts, just like cond – the first part (the "channel op") is used to specify a channel that alt! should wait on, and the second part (the "result expr") specifies what should happen if that channel delivers a value first.

Since you probably want to access the value delivered by the channel or the channel itself when this happens, the result expr gives you the opportunity to bind both the value and the channel to symbols, and a body of code to execute with those bindings. Thus, the following clause…

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

…means:

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

and the following clause…

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

…means:

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

Altogether, these two clauses would be written as:

(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)))
like image 56
erikprice Avatar answered Jan 16 '23 18:01

erikprice