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.

Reply via email to