Search code examples
clojure

Use core.async's >! and <! outside go blocks


I'm trying to implement a (very) simple actor model prototype in clojure. Each actor would have, as the loop to handle the arrival of messages, a go-loop. I wanted to invoke, inside this go-loop, functions that would either take from or put into a channel. I really wanted parking behaviour on these inner channel operations, but I can't actually use <! or >! to do it so, because the operations wouldn't be directly inside the go-loop. Can I use macros to circumvent such limitation? If so, how would I do it?

To illustrate the issue simply, in the following snippet, how can I change foo so that the code actually compiles and I get parking behaviour?

(defn main-loop
  [ch]
  (async/go-loop [] (foo ch) (recur)))
(defn foo [ch] (>! ch "Hello, World!"))

Solution

  • You can use macros to write any code that you could write by hand, and that's all. So if you just want your functions to be convenient shorthand for using >! inline, then sure, you can replace the functions with macros. If you want to do something fancier, like map that function over a list of messages, then you can't, because that would involve bundling them up in a function to pass to map.

    A simple example would just be

    (defmacro foo [ch]
      `(>! ~ch "Hello, World!"))
    

    Whether this is the solution to your problem, or something else is (such as using >!!), depends on what you want to be able to do with these things.