Green Eggs and Transducers
A quick tour of Clojure Transducers with core.async with Dr. Seuss as a guide.
Follow along at home by:
lein new green-eggs
- modify your project.clj to include the following:
1 2 3 4 5 6 7 |
|
- Start up a repl and hack in!
Green Eggs and Ham
Transducers are a new feature of Clojure 1.7. Instead of trying to explain them with words, let’s take a look of them in action. First we need some data. Let’s def a vector of all the places you could try green eggs and ham.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Next, let’s create a function that will transform the places into a “I would not eat them …” sentence.
1 2 3 4 5 |
|
We also need a function to take this result and actually try the green eggs and ham.
1 2 3 4 5 |
|
Now we have two transformations that we can apply to the vector of green-eggs-n-ham strings. One of the really nice things about transducers is that you can describe and compose this transformation without a data structure present.
1 2 3 4 |
|
We can run the transformation of the transducers against the data in a few ways.
- into: Non-lazy turn the transformation into a collection
- sequence: Same thing but lazy
- transduce: Acts like reduce on the all the transformed elements
- With core.async channels doing the transformations.
Let’s look at the green eggs and ham example for each one of these ways:
Into
Into takes a transducer and collection to work on and returns the vector we asked for:
1 2 3 4 5 6 7 8 9 |
|
Sequence
Sequence takes similar arguments, but as promised, returns a lazy sequence that we can interact with.
1 2 3 4 5 |
|
Transduce
If we want to finally arrange all our sentences in the vectors into one string, we would use reduce. The way to do this with transducers is to use transduce. It takes a function of two arguments to perform the reduce, as well as an initial data input.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Core.async
Core.async has a really nice way to define channels with a transducer that will transform each element on the channel.
1
|
|
Let’s define another channel to reduce the results of the sam-i-am-chan to a string.
1
|
|
Finally, let’s actually put the green-eggs-n-ham data onto the sam-i-am-chan and let the data transformations flow….
1
|
|
At last, we can get our result off the result channel and revel in the beauty of asynchronous data transducers.
1 2 3 4 5 6 7 8 9 10 11 |
|
Transducers are elegant and powerful, just like the rest of Clojure. Try them, you will like them :)