This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-07-29
Channels
- # admin-announcements (48)
- # announcements (1)
- # beginners (80)
- # boot (150)
- # cljs-dev (12)
- # clojure (133)
- # clojure-dev (1)
- # clojure-italy (27)
- # clojure-japan (1)
- # clojure-russia (77)
- # clojurescript (236)
- # clojutre (3)
- # code-reviews (1)
- # core-async (14)
- # core-logic (4)
- # core-matrix (15)
- # cursive (5)
- # datomic (30)
- # editors (16)
- # events (1)
- # hoplon (1)
- # ldnclj (17)
- # off-topic (30)
- # om (2)
- # onyx (47)
- # reagent (8)
If you watch any of the videos with Rob Pike talking about CSP he gives an example of using channels to calculate prime numbers using the Sieve of Eratosthenes technique, which is pretty cool. So I went looking for examples of this in Clojure and didn't find any that seemed idiomatic, particularly now that we have transducers. So I wrote one and would like some feedback since I don't have much experience with core.async. Let me know how this can be improved:
;; Sieve of Eratosthenes Prime Number Generator
(defn chan-of-primes []
(let [ints (chan)
primes (chan)]
(go-loop [n 2]
(>! ints n)
(recur (inc n)))
(go-loop [cur-ch ints]
(let [prime (<! cur-ch)
new-ch (chan 1 (filter #(not= 0 (mod % prime))))]
(>! primes prime)
(pipe cur-ch new-ch)
(recur new-ch)))
primes))
I wanted something that would return a channel with an infinite stream of prime numbers.
@martintrojer did one: https://github.com/martintrojer/go-tutorials-core-async/blob/master/src/sieve.clj
@erik_price: no offense, but that code could be better
it creates a channel in its global namespace, has a hardcoded limit of 100 primes, and uses println inside its loop
@erik_price: Why?
I think it was just intended to demonstrate how you could use core.async to do something, not win a code quality competition. But I shouldn’t assume I know anything about what its author intended.
To be fair, prime calculation is a bad application for CSP... example is just an example
@pat @erik_price that was a straight up port of https://github.com/martintrojer/go-tutorials-core-async/blob/master/src/sieve.go (one of Mr Pikes examples)
Prime calculation might be a bad application for CSP, but it can still be a good example for how best to write code using core.async and transducers, which, if you read my post, was my original point. So, here is what I've done to make better use of the composable nature of transducers:
(defn chan-of-ints-x [start-n xform]
(let [ints (chan 1 xform)]
(go-loop [n start-n]
(>! ints n)
(recur (inc n)))
ints))
(defn chan-of-primes-x []
(let [primes (chan)]
(go-loop [cur-xf (map identity)
cur-ch (chan-of-ints-x 2 cur-xf)]
(let [prime (<! cur-ch)
new-xf (comp cur-xf (filter #(not= 0 (mod % prime))))
new-ch (chan-of-ints-x prime new-xf)]
(>! primes prime)
(recur new-xf new-ch)))
primes))
What's a good way to benchmark the two versions of the code I've posted? The latter appears to run faster, but I haven't done any benchmarking in Clojure so if anyone would like to help me with that it would be greatly appreciated.
Here are some more thoughts that I didn't really explicitly say the first time. Clojure's core.async was influenced by golang and Rob Pike's work with channels. Rob likes to show the example of calculating primes using channels. Wouldn't it be nice to have a canonical example of the same in Clojure?