This is what I ended up building:
(defmacro wrap-error [& body] `(slingshot.slingshot/try+ (let [ans# ~body] {:tag :ok :message ans#}) (catch Exception e# {:tag :error :message e#}))) (defmacro wgo [& body] `(clojure.core.async/go (wrap-error ~@body))) (defmacro ?>!! [chan msg] (let [c (gensym)] `(let [~c ~chan] (and (not @(.-closed ~c)) (not= :chan-full (async/alts!! [[~c ~msg]] :default :chan-full)))))) (defmacro ?>! [chan msg] (let [c (gensym)] `(let [~c ~chan] (and (not @(.-closed ~c)) (not= :chan-full (async/alts! [[~c ~msg]] :default :chan-full)))))) (defmacro ?<! [chan] `(hmatch (clojure.core.async/<! ~chan) [:ok value#] value# [:error error#] (slingshot.slingshot/throw+ error#))) (defmacro ?<!! [chan] `(hmatch (clojure.core.async/<!! ~chan) [:ok value#] value# [:error error#] (slingshot.slingshot/throw+ error#))) So for example, with ?>!! and ?>! I want to do a "put-if-possible-other-return-false". Normally, I'd like to write this as a function, i.e. (defn put-if-possible-other-return-false! ... ) but in this particular case, I seem to be forced to use a macro. On Mon, Jan 13, 2014 at 8:01 PM, Timothy Baldridge <tbaldri...@gmail.com>wrote: > This is a often asked question, but one I think requires a bit of thought. > The key to solving this kind of issue in your code is to think of channel > ops as "io" and as side-effecting. It's tempting to stick these operations > deep inside nested functions, but I think that's rather "un-functional", > and "un-clojureish". In pure functional programming we try to keep the io > at the edges. > > So this is the pattern I try to follow when writing core.async code: keep > the core functionally pure, and the side effects to the edges. This has > several nice side effects: > > 1) Your functionally pure code is now much easier to test, you can rip off > the core.async specific bits and test the core synchronously. > > 2) Your inputs and outputs are now in a single place, and so are easier to > reason about. > > As mentioned above, you can still wrap function bodies in gos, if needed. > And you can use core.async/put! and take! from anywhere in your code. But I > do recommend trying to avoid jumping to these by default. > > That being said, creating gos is quite cheap. On my MBP, after the JIT has > warmed up, I'm estimating the CPU cost of creating a go is about 140ns > (yes, ns). So creating them may not be the bottleneck they seem to be at > first. (and take that number with a big grain of salt). > > Just some points to ponder. > > Timothy Baldridge > > > On Mon, Jan 13, 2014 at 6:05 PM, t x <txrev...@gmail.com> wrote: > >> Hi Stephen, >> >> I now understand what you meant. Thanks writing a minimal test case. >> >> >> On Mon, Jan 13, 2014 at 3:34 PM, Stephen Cagle <same...@gmail.com> wrote: >> >>> And already, I see that the first one should have been >>> >>> (defn test [] >>> (async/go >>> (println (async/<! (foo))))) >>> >>> Boy I wish you could edit this post after the fact. >>> >>> On Monday, January 13, 2014 3:32:39 PM UTC-8, Stephen Cagle wrote: >>>> >>>> I just want to re-iterate that there are many (some are probably >>>> better) ways to do this, but using what I suggested above it would be: >>>> >>>> (defn foo [] >>>> (async/go "hi")) >>>> >>>> (defn test [] >>>> (println (async/<! (foo)))) >>>> >>>> (defn test [] >>>> (let [c (async/chan 10)] >>>> (async/go >>>> (async/>! c (async/<! (foo))) >>>> (println (<! c))))) >>>> >>>> (test) >>>> >>>> I wrote the first (test) minimally as you aren't really doing anything >>>> with your 10 slot buffer. However, in real code maybe you are, so I tried >>>> to write the second (test) in the fashion that you wrote it. >>>> >>>> There is nothing really to what I am saying other than that, yes, the >>>> core.async codewalker cannot see into code that you call into. Therefore, >>>> if the code you call into also needs to do asynchronous things, you need to >>>> wrap it in something like a go block as well. With the above solution you >>>> might have 2 go machines "live" at the same time (the test and the foo go >>>> machines). >>>> >>>> In short, you have a trade-off here. If you want to modularize your >>>> code at the function (go machine) level, you are going to potentially have >>>> multiple go machines "live" at the same time. >>>> >>>> I don't have an editor/compiler on this tablet, so apologies for any >>>> silly errors. >>>> >>> -- >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To post to this group, send email to clojure@googlegroups.com >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> To unsubscribe from this group, send email to >>> clojure+unsubscr...@googlegroups.com >>> For more options, visit this group at >>> http://groups.google.com/group/clojure?hl=en >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to clojure+unsubscr...@googlegroups.com. >>> For more options, visit https://groups.google.com/groups/opt_out. >>> >> >> -- >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clojure@googlegroups.com >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+unsubscr...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/groups/opt_out. >> > > > > -- > “One of the main causes of the fall of the Roman Empire was that–lacking > zero–they had no way to indicate successful termination of their C > programs.” > (Robert Firth) > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.