Welcoming Rich Hickey to the Staples Innovation Lab

I’m pleased to announce that Rich Hickey has come aboard the Staples Innovation Lab as Technical Advisor. He will provide architectural and general technical oversight across all the products we’re building. These include things like dynamic and personalized pricing, product recommendation engines, email targeting and behavioral retargeting, a new search engine, shipping delivery optimization, etc.

We’re already heavy users of Clojure, Datomic, ClojureScript, Simulant, and Pedestal. So this just makes a ton of sense for us… we’re also working with Cognitect on several initiatives, so having Rich’s oversight will just add to the awesomeness of the team.

Please join me in welcoming Rich to the lab!

P. S. Get in touch with me if you’d like to explore opportunities working with the Clojure stack at the second largest E-Commerce operation in the world.

Filed under: Uncategorized

TL;DR

Elastisch is a battle tested, small but feature rich and well documented Clojure client for ElasticSearch. It supports virtually every Elastic Search feature and has solid documentation.

2.0.0-beta1 is a preview release of Elastisch 2.0, which focuses on ElasticSearch 1.0 compatibility.

Changes between Elastisch 1.4.0 and 2.0.0

ElasticSearch 1.0 Compatibility

Main goal of Elastisch 2.0 is ElasticSearch 2.0 compatibility. This includes minor API changes (in line with ElasticSearch 1.0 API and terminology changes) and moderate internal modifications.

Support for cluster nodes stats and info REST APIs

`clojureworkz.elastisch.rest.admin/nodes-info` and `clojureworkz.elastisch.rest.admin/nodes-stats` are new administrative functions that provide access to ElasticSearch cluster stats and node info.

Examples:

See ElasticSearch nodes stats documentation, nodes info page, and node specification page for more info.

Contributed by Joachim De Beule.

Support for _cluster/state REST API

Added `(clojureworkz.elastisch.rest.admin/cluster-state & {:as params})`

Examples:

Contributed by Joachim De Beule.

Support for _cluster/health REST API

Added `(clojureworkz.elastisch.rest.admin/cluster-health & {:as params})`

Example:

Contributed by Joachim De Beule.

Support for analyze in REST API client

Added `(doc/analyze text & {:as params})`

Examples:

Contributed by Joachim De Beule

Query String Escaping

`clojurewerkz.elastisch.query/query-string` accepts a new option, `:escape-with`, which is a function that performs escaping of special characters in query string queries.

By default `clojurewerkz.elastisch.escape/escape-query-string-characters` is used.

Contributed by Ben Reinhart (Groupon).

Elastisch now depends on ElasticSearch native client version `1.0.1`.

clj-http Update

clj-http dependency has been upgraded to version `0.9.0`.

Full Change Log

Elastisch change log is available on GitHub.

Thank You, Contributors

Kudos to Richie Vos for contributing to this release.

Elastisch is a ClojureWerkz Project

Elastisch is part of the group of libraries known as ClojureWerkz, together with

• Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
• Monger, a Clojure MongoDB client for a more civilized age
• Cassaforte, a Clojure Cassandra client
• Titanium, a Clojure graph library
• Neocons, a client for the Neo4J REST API
• Welle, a Riak client with batteries included
• Quartzite, a powerful scheduling library

and several others. If you like Elastisch, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

Michael on behalf of the ClojureWerkz Team

Clojure Gazette 1.69

Clojure Gazette 1.69

 Summers,

Issue 1.69 March 09, 2014

Editorial

Hello!

Enjoy the issue!

Sincerely,
Eric Normand
<ericwnormand@gmail.com>

The Developer to Watch

Zach Tellman

Zach Tellman has created a handful of libraries that make Clojure development faster and closer to the metal without sacrificing the abstractions we have all come to rely on in Clojure. Check out his Github repos. He's also interesting on Twitter. Check out his blog. Also, get in touch with him and let him know I sent you!

Summer of Code

Typed Clojure Request for Mentors for GSOC 2014

Ambrose Bonnaire-Sergeant is administering several Google Summer of Code projects related to Typed Clojure. He is looking for mentors who can take a small amount responsibility for the students. There are several exciting projects that students will tackle this summer, all promising to improve the Clojure experience. If you're interested, reply to the mailing list.

core.async

Working with core.async

This is a series of three (and maybe more to come) experience reports using core.async.

Legend

Tony Hoare Bibliography

I came across this gem of a page when searching for information about Tony Hoare. Apparently, he's still doing research and publishing at Oxford. This bibliography has links to many papers in PDF form. Start with The Emperor's Old Clothes (his Turing Award Lecture). After that, maybe Communicating Sequential Processes, the source of the idea behind core.async.

Symbolic computation

The Secret Life of a Mathematica Expression

David Leibs explores the proprietary language that comes with Mathematica. I've been thinking about Mathematica when I saw a preview video of the Wolfram Language.

Setting Up Travis CI for OpenCV and Midje

I’ve been fiddling with OpenCV for a few weeks. Using OpenCV and Clojure is straightforward. The hardest part was setting up OpenCV.

When I’m experimenting and I get to a place where I feel like I know what I’m doing, I’ll start writing tests. Eventually you’ll setup continuous integration, but then you remember how difficult installing OpenCV was! If you’d like to use Travis CI with your Clojure project using OpenCV, I’ve already done the work for you! Swapping out midje isn’t a problem, if you’d rather use core.test or speclj, but I’m going to focus on midje here.

I’m assuming your project looks something like Magomimmo’s opencv-start. He’s also the guy that wrote the Clojure tutorial on OpenCV’s documentation site. If you setup your project using those instructions, that is fine since they are almost identical. The only difference is that I’m using a more more up to date version of OpenCV. You will have to make a few changes to the Travis CI yaml configuration below if you want to use a different version.

First, we need to add the midje and lein localrepo plugins to our project.clj if they aren’t there already. Travis CI needs to know about them. Adding the following line inside defproject within your project.clj should suffice:

```clojure :plugins [[lein-localrepo "0.5.3"] [lein-midje "3.1.3"]] ```

Next, we need to add the `.travis.yml` config to the root of the repo:

```yaml language: clojure lein: lein2 script: lein2 midje jdk: – oraclejdk7

compiler: – gcc

before_install: – sudo apt-get update

install: – sudo apt-get install python-dev python-numpy

before_script: – git clone https://github.com/Itseez/opencv.git – cd opencv – git checkout 2.4 – mkdir build – cd build – cmake .. – make -j8 – sudo make -j8 install – cd ../.. – mkdir -p native/linux/x86_64 – cp opencv/build/lib/libopencv_java248.so native/linux/x86_64/libopencv_java248.so – cp opencv/build/bin/opencv-248.jar . – jar -cMf opencv-native-248.jar native – lein2 localrepo install opencv-248.jar opencv/opencv 2.4.8 – lein2 localrepo install opencv-native-248.jar opencv/opencv-native 2.4.8 ``` With this configuration, we tell Travis CI that: our project is a Clojure project, that we are using Leiningen 2.0, midje for testing, and Oracle JDK 7. The lines after that are for building OpenCV.

The lines before `before_script` tell Travis CI that: we need to use the GCC compiler, install python dev dependencies, and numpy for OpenCV. The lines in `before_script` are the actual build process automation for OpenCV.

If you noticed that the `before_script` is similar to the build steps in Magomimmo’s tutorial, you would be right. The only change I made was to use OpenCV 2.4.8. If you’d like to use a different release, you should change the `before_script` to match your needs. On Travis CI, the build process takes about 8 minutes.

This Wednesday we’re performing algorithmic visuals for IJAD Dance‘s showing of In-Finite Space as part of the AHRC Creative Economy showcase. Twitter messages are geometrically formatted in 3D and cast into a retro-aesthetic graphical fly-through sequence to be interpreted by the dancers. Technology: Field, hybrid Python/Clojure mix.

Optimization with Loco

I had the pleasure of beta-testing Loco, which was announced today. Loco is a Clojure constraint solver library built on top of the Java library Choco. There are several constraint libraries available for Clojure, including core.logic, propaganda, and clocop, each with a slightly different focus.

The features that make Loco shine are the performance of the constraint engine, the fully declarative API, the ease with which one can build models, support for several interesting global constraints, and the ability to find an optimal solution for models with multiple solutions.

This is the first article of what I hope to be a series, detailing some of the interesting problems you can solve with Loco.

Scheduling Buses with Loco

``(use 'loco.core loco.constraints)``

Loco is a powerful and expressive constraint solver, but it can also be used to solve certain kinds of integer linear programs.

One classic example is bus scheduling. Imagine that we are city transportation planners and we want to minimize the number of buses we need to operate in order to meet demand. We know the number of buses demanded for four-hour blocks of time.

``(def demands  {:12am-4am  8   :4am-8am  10   :8am-12pm  7   :12pm-4pm 12   :4pm-8pm   4   :8pm-12am  4})``

So for example, this map tells us that there is sufficient demand for 8 buses operating between 12am and 4am.

The interesting twist is that buses operate for 8 hours at a time. So, if we set a bus into operation at 12am, it operates an 8-hour shift from 12am-8am. So the question is, how many buses do we need to run from 12am-8am, and from 4am-12pm, etc. in order to meet the above demands.

We can represent this by a series of variables, each of which must be an integer from 0 through 12 (since 12 is the maximum overall demand).

So with loco, we can get the solution quite simply:

``(solution  [(\$in :bus-12am-8am 0 12)   (\$in :bus-4am-12pm 0 12)   (\$in :bus-8am-4pm 0 12)   (\$in :bus-12pm-8pm 0 12)   (\$in :bus-4pm-12am 0 12)   (\$in :bus-8pm-4am 0 12)   (\$>= (\$+ :bus-8pm-4am :bus-12am-8am) (demands :12am-4am))   (\$>= (\$+ :bus-12am-8am :bus-4am-12pm) (demands :4am-8am))   (\$>= (\$+ :bus-4am-12pm :bus-8am-4pm) (demands :8am-12pm))   (\$>= (\$+ :bus-8am-4pm :bus-12pm-8pm) (demands :12pm-4pm))   (\$>= (\$+ :bus-12pm-8pm :bus-4pm-12am) (demands :4pm-8pm))   (\$>= (\$+ :bus-4pm-12am :bus-8pm-4am) (demands :8pm-12am))]  :minimize  (\$+ :bus-12am-8am :bus-4am-12pm :bus-8am-4pm       :bus-12pm-8pm :bus-4pm-12am :bus-8pm-4am))``

which yields

``{:bus-8pm-4am 0, :bus-4pm-12am 4, :bus-12pm-8pm 7,  :bus-8am-4pm 5, :bus-4am-12pm 2, :bus-12am-8am 8}``

Let’s see if we can generalize this to handle an arbitrary number of evenly-spaced time periods. Clearly, to do this we’ll need to get away from demands and variables that directly name the timespan. Instead, for our example in which we sliced the day into six 4-hour time periods, we can imagine indexing these blocks of time (0-based) as “Time period 0” through “Time period 5”. So we can just use a vector for our demands, for example:

``[8 10 7 12 4 4]``

means that 8 buses are demanded for time period “0” (corresponding to 12am-4am), 10 buses are demanded for time period “1” (corresponding to 4am-8am),… up to a demand of 5 buses for time period “5”.

We’ll make use of Loco’s ability to treat vectors as subscripted variables. So `[:buses 0]` denotes $buses_0$, which is our variable for how many buses we schedule starting at the beginning of time period 0 (i.e., 12am). `[:buses 1]` (i.e., $buses_1$) is the variable for the number of buses starting at the beginning of time period 1, etc.

We will also need an input, `span` which indicates how many consecutive time periods are spanned by the bus’s shift. In our example, `span` would be 2 (because a bus works for 2 of our 4-hour time periods).

``(defn minimize-buses  "Takes a vector of the demands for any number of equally-spaced time slots.   span is the number of time slots that a bus's operating time spans"  [demands span]  (let [time-slots (count demands),        max-demand (apply max demands),        declarations        (for [i (range time-slots)]          (\$in [:buses i] 0 max-demand))        constraints        (for [i (range time-slots)]          (\$>=            (apply \$+ (for [j (range (inc (- i span)) (inc i))]                        [:buses (mod j time-slots)]))            (demands i)))]    (solution      (concat declarations constraints)      :minimize (apply \$+ (for [i (range time-slots)] [:buses i])))))``

Let’s test it out on our original sample demand:

``=> (minimize-buses [8 10 7 12 4 4] 2){[:buses 5] 0, [:buses 4] 4, [:buses 3] 7, [:buses 2] 5, [:buses 1] 2, [:buses 0] 8}``

Hmmm, it’s a little hard to read. We can fix that:

``=> (into (sorted-map) (minimize-buses [8 10 7 12 4 4] 2)){[:buses 0] 8, [:buses 1] 2, [:buses 2] 5, [:buses 3] 7, [:buses 4] 4, [:buses 5] 0}``

Good, same answer as before. But now we can easily adjust to alternative demand schedules. For example, here’s a solution for a demand schedule based on 2-hour time periods, while buses still work 8-hour shifts:

``=> (into (sorted-map)      (minimize-buses [1 5 7 9 11 12 18 17 15 13 4 2] 4)){[:buses 0] 0, [:buses 1] 1, [:buses 2] 2, [:buses 3] 6, [:buses 4] 2, [:buses 5] 2, [:buses 6] 8, [:buses 7] 5, [:buses 8] 0, [:buses 9] 0, [:buses 10] 0, [:buses 11] 4}``

Now, let’s try a demand schedule with 1-hour time periods, with buses working 8-hour shifts:

``=> (into (sorted-map)      (minimize-buses        [1 3 5 7 9 11 12 13 14 15 16 19         18 17 15 13 15 16 10 8 6 5 4 2]        8))``

Uh oh, this seems to run forever. We can fix this with the timeout feature. In the definition of `minimize-buses`, we change the call to `solution` as follows:

``(solution      (concat declarations constraints [constraint])      :minimize (apply \$+ (for [i (range time-slots)] [:bus i]))      :timeout 1000)``

The `:timeout` keyword specifies a number of milliseconds, after which the solver should return the best solution it has found so far:

``=> (into (sorted-map)      (minimize-buses        [1 3 5 7 9 11 12 13 14 15 16 19         18 17 15 13 15 16 10 8 6 5 4 2]        8)){[:bus 0] 1, [:bus 1] 2, [:bus 2] 2, [:bus 3] 2, [:bus 4] 2, [:bus 5] 2, [:bus 6] 1, [:bus 7] 1, [:bus 8] 2, [:bus 9] 3, [:bus 10] 3, [:bus 11] 5, [:bus 12] 1, [:bus 13] 1, [:bus 14] 2, [:bus 15] 2, [:bus 16] 2, [:bus 17] 0, [:bus 18] 0, [:bus 19] 0, [:bus 20] 0, [:bus 21] 0, [:bus 22] 0, [:bus 23] 0}``

Written with StackEdit.

Appointment scheduling in Clojure with Loco

Loco makes it easy to declaratively build constraint satisfaction models. In this blog post, we’ll look at a common use for constraint programming – appointment scheduling – and in so doing, we’ll see some of the ways that Loco goes beyond the features found in other Clojure constraint libraries.

``(use 'loco.core 'loco.constraints)``

Scheduling appointments with no conflicts

Imagine you have four people coming in for an interview, and you’ve set aside four timeslots in your day to conduct these interviews. You ask each person to list the timeslots when he/she can potentially come in.

Let’s use 0-based indexing to refer to the people, and 1-based indexing to refer to the timeslots.

Person 0 says she can come in at any of the four timeslots: 1, 2, 3, or 4.
Person 1 says he can come in at timeslot 2 or 3.
Person 2 says she can come in at timeslot 1 or 4.
Person 3 says he can come in at timeslot 1 or 4.

So the availability data looks like this:

``(def availability  [[1 2 3 4]   [2 3]   [1 4]   [1 4]])``

Let the variable `[:person 0]` denote the timeslot when person 0 is scheduled to come in, `[:person 1]` when person 1 comes in, etc.

``(def person-vars  (for [i (range (count availability))] [:person i]))``

We want to constrain each `[:person i]` variable to the available timeslots.

``(def availability-constraints  (for [i (range (count availability))]    (\$in [:person i] (availability i))))``

We want to ensure we don’t schedule two people in the same timeslot.

``(def all-different-constraint  (apply \$all-different? person-vars))``

For convenience, let’s assemble the constraints into one big list (the order doesn’t matter in Loco):

``(def all-constraints   (conj availability-constraints all-different-constraint))``

Now we’re ready to solve. Let’s dump the solution into a sorted-map for easy readability.

``=> (into (sorted-map) (solution all-constraints)){[:person 0] 3, [:person 1] 2, [:person 2] 4, [:person 3] 1}``

So there you have it. Once we’ve played around with this example interactively in the REPL, and are confident in the model, we can easily abstract this into a function that takes availability data, and returns the schedule:

``(defn schedule [availability]  (->>    (solution      (conj        (for [i (range (count availability))]          (\$in [:person i] (availability i)))        (\$distinct          (for [i (range (count availability))] [:person i]))))    (into (sorted-map))))=> (schedule     [[1 3 5]      [2 4 5]      [1 3 4]      [2 3 4]      [3 4 5]]){[:person 0] 5, [:person 1] 4, [:person 2] 1, [:person 3] 2, [:person 4] 3}``

I think the declarative Loco way of modeling constraints is concise and elegant, but this example could just as easily be done in, say, `core.logic`. So let’s push beyond, into an area that (as far as I know) can’t be done with `core.logic`.

Scheduling appointments minimizing conflicts

The above scheduler is somewhat naive.

``=> (schedule      [[1 2 3 4]      [1 4]      [1 4]      [1 4]]){}``

This doesn’t work because there’s no way to satisfy the constraint that no two people can be scheduled in the same timeslot.

But let’s say, hypothetically, that if absolutely necessary, we can potentially squeeze two candidates into the same timeslot. We’d rather not, but we can do it if we have to. Can we build a model for this?

Again, let’s start exploring the problem interactively with global defs and playing around with it at the REPL. Here’s the problematic availability example:

``(def availability  [[1 2 3 4]   [1 4]   [1 4]   [1 4]])``

As before, we’ll want to constraint each person’s timeslot to his/her availability schedule:

``(def availability-constraints  (for [i (range (count availability))]    (\$in [:person i] (availability i))))``

Let’s define a few names for convenience. Let `timeslots` be a list of all the timeslot numbers.

``(def timeslots (distinct (apply concat availability)))``

Let `person-vars` be the list of all `[:person i]` variables.

``(def person-vars  (for [i (range (count availability))] [:person i]))``

Now for the interesting part. We want to allow up to 2 people in a given timeslot. So we’ll let the variable `[:num-people-in-timeslot 1]` be the number of people signed up for timeslot 1, and so on. Let `people-in-timeslot-vars` be the list of all such variables.

``(def people-in-timeslot-vars  (for [i timeslots] [:num-people-in-timeslot i]))``

Now, we create a list of constraints that state that each of these `[:num-people-in-timeslot i]` variables ranges between 0 and 2.

``(def conflict-constraints  (for [i timeslots]    (\$in [:num-people-in-timeslot i] 0 2)))``

To give these :num-people-in-timeslot variables the appropriate meaning, we need to bind each `[:num-people-in-timeslot i]` variable to the number of times `i` occurs among the variables `[:person 1]`, `[:person 2]`, etc. Loco’s `\$cardinality` constraint allows us to do exactly that. For example,

``(\$cardinality [:x :y :z] {1 :number-of-ones})``

will bind :number-of-ones to the number of times 1 occurs among :x, :y, and :z. So, the following constraint will bind all the `[:num-people-in-timeslot i]` variables to their appropriate values.

``(def number-in-timeslots  (\$cardinality person-vars                (zipmap timeslots people-in-timeslot-vars)))``

To minimize the number of conflicts, we need to count the number of conflicts.

Let the variable `:number-of-conflicts` stand for the number of timeslot conflicts we have. We need two constraints on `:number-of-conflicts`. The first constraint just sets up the finite domain that the variable could range over (i.e., 0 to the total number of timeslots). We need to do this because in Loco, every variable must be declared somewhere in the model. The second constraint binds `:number-of-conflicts` to the number of times `2` appears in the variables `[:num-people-in-timeslot 1]`, `[:num-people-in-timeslot 2]`, etc.

``(def number-of-conflicts  [(\$in :number-of-conflicts 0 (count timeslots))    (\$cardinality people-in-timeslot-vars {2 :number-of-conflicts})])``

We built the constraints in parts; now building the model is simply a matter of concatting all the constraints together. (Note that `number-in-timeslots` is a single constraint, so we concatenate `[number-in-timeslots]` in with the other lists of constraints).

``(def all-constraints (concat availability-constraints                             conflict-constraints                             [number-in-timeslots]                              number-of-conflicts))``

Now, we’re all set up to solve the model.

``=> (solution all-constraints             :minimize :number-of-conflicts){[:person 0] 2, [:person 1] 4, [:person 2] 4, [:person 3] 1, :number-of-conflicts 1, [:num-people-in-timeslot 1] 1, [:num-people-in-timeslot 2] 1, [:num-people-in-timeslot 3] 0, [:num-people-in-timeslot 4] 2}``

In the final version, we really only want to see the `[:person i]` variables; Loco allows us to hide the other variables from the output by prepending an underscore character in front of the variable names.

So let’s abstract this into a more robust `schedule-with-conflicts` function.

``(defn schedule-with-conflicts [availability]  (let [timeslots (distinct (apply concat availability)),        availability-constraints        (for [i (range (count availability))]          (\$in [:person i] (availability i))),        person-vars        (for [i (range (count availability))] [:person i]),        people-in-timeslot-vars        (for [i timeslots] [:_num-people-in-timeslot i]),        conflict-constraints        (for [i timeslots]          (\$in [:_num-people-in-timeslot i] 0 2)),        number-in-timeslots        (\$cardinality person-vars                       (zipmap timeslots people-in-timeslot-vars)),        number-of-conflicts        [(\$in :_number-of-conflicts 0 (count timeslots))          (\$cardinality people-in-timeslot-vars {2 :_number-of-conflicts})]        all-constraints (concat availability-constraints                                conflict-constraints                                [number-in-timeslots]                                number-of-conflicts)]    (into (sorted-map)          (solution all-constraints :minimize :_number-of-conflicts))))``

Let’s give it a spin:

``=> (schedule-with-conflicts       [[1 2 3 4]        [1 4]        [1 4]        [1 4]]){[:person 0] 2, [:person 1] 4, [:person 2] 4, [:person 3] 1}``

Written with StackEdit.

Working with core.async: Exceptions in go blocks

Dealing with exceptions in go blocks/threads is different from normal clojure core. This gotcha is very common when moving your code into core.async go blocks -- all your exceptions are gone! Since the body of a go block is run on a thread pool, it's not much we can do with an exception, thus core.async will just eat them and close the channel. That's what happened in the second snippet in this post. The `nil` result is because the channel we read from is closed.

I find myself wanting to know the cause of problem at the consumer side of a channel. That means the go block needs to catch the exception, put it (the exception) on the channel before it dies. David Nolen has written about this pattern, and I've been using the proposed `<?` quite happily.

If you're interested in how some Go examples convert to core.async check out this repo.

Working with core.async: Chaining go blocks

One particularly annoying difference between the core.async and Go is that you can't wrap function calls with the `go` macro. This is due to implementation details of core.async, which can only see the body 'inside' the macro and not the functions it may call. This is obviously not a problem if the called function doesn't interact with any channels, but if it does when you might be in trouble. I've touched on this subject in a previous post.

Anyway, let me explain what I mean.

Let's say we have a complicated `get-result` function that hits some external services (waits for the result) and then feeds the input to a big calculation function multiple times. All examples below simplified for brevity.

This is all fine and well, but lets say the calculation function also needs to wait on some data, so it needs to become a go-routine as well. This means that we no longer have a return value but a channel with the result. Lets use some FP to get all the data out.

Nope, you can't to that, `Assert failed: <! used not in (go ...) block`. It's also 'returns' nil, explained in this post. Let's try another way;

Oh dear, 2 orders of magnitude and that warm fuzzy FP feeling is gone.

Since a go block returns a channel (with the result), you now have to deal with taking that value out of the channel. If you have long 'go-call-chains' of go blocks, you're going to spend lots of time in and out of channels. In this case we have lock congestion amongst all the `calculation-go2` blocks and that single channel.

The nil returning snippet above can be written in a similar fashion using some of core.async's helpers functions (thanks to Ben Ashford for pointing this out);

Unfortunately this performs even worse than the written out go-loop, but it is much nicer.

How is this any better in Go?

Here's a rough equivalent of the 2 scenarios in Go.

The key difference is that the caller put the function in a go block, and then any subsequent function are free to operate on any channel without itself being wrapped in `go`.

Also it performs better `getResult2` is an order of magnitude slower than `getResult`.

The blessings and curses of macros

If we have to wrap every function in a go block and if chaining go blocks is so slow, can we just inline that function in our outer go block somehow? Yes we can, we can turn that function into a macro.

Problem solved right? Well, not really. Instead of composable functions (well kind of since they return channels) we now have a special kind of macros that must be called from within a go block. In the snippet above we can't use the lovely `(reduce ... (repeatedly calculation-go-macro))` form since we can't use macros that way. However, the macro itself can use `<!`, `>!` etc freely without the `go` wrapper and we solved the perf problem.

If you're interested in how some Go examples convert to core.async check out this repo.