I went to the Boulder Clojurians meetup tonight where we discussed core.async. One of the topics of discussion was helper functions that help you work with core.async. I’ve worked with it a few times in the past, and here are a few of the things I seem to do (almost) every time.

Callback to Async

Sometimes, you have a function that is asynchronous via a callback, such as with http-kit.client, or when working with nodejs. To convert these functions into channel-based operations can be tedious, so lets just use a function for it!

Imagine a function (f a b callback) where callback is an (fn [value]). Let’s create a function (or macro) so we can do (go (<! (cb->async f a b)))

A first cut using a function:

This is a pretty nice tool for working with callback-based functions. But we can make it better! First, we can use async/onto-chan instead of #(go (>! c %)). Secondly, we can “inline” the call by using a macro.

Here’s a revised implementation, this time for use with nodejs.

Both these implementations are valid, and the function form is more readable. You can also determine which “put” function is more readable: (onto-chan c [%]) or (go (>! c %)).

Async as Promise

core.async provides a lot of functionality for comparatively little syntactical overhead. But it doesn’t always provide helpers for all the use-cases. One case I seem to use a lot (especially in clojurescript) is promises. I like the flexibility of core.async, but I want more promise-like helpers.

Luckily, the library recently released core.async/promise-chan, which acts like a promise, containing only ever one value.

Astute observers will note that promise-map is the promise functor’s fmap function, while then is the promise monad’s bind function.

Don’t rewrite the wheel

There are so many goodies in the core.async library that you probably don’t need to write a bunch of generic helper functions.

  • For connecting tasks, checkout pipe and the pipeline-* family of functions.
  • mult and tap help with stream processing while pub and sub do what you think they do.
  • split is useful for splitting channels, such as errors from successful values.