[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)))
[c t]
is a vector of ports.[val ch]
is a binding (as you said).ch
is the channel that could be taken from; andval
is the value taken . Functionfoo
is then evaluated using that binding. See gist.github.com/konacaret/d1f5c19cfbe46d3b97a3 for a simple example of this. – Silverside