Your description of what is going on with my macro was really helpful. In
my head I was imagining recursive evals running over the code, saying
first, then, etc. I didn't really think about compile time vs. run-time.
I am impressed with James' code as well, but I am having trouble fully
understanding it and getting it to run. From the transparent put
definition, it doesn't seem like it is possible to pass a channel value as
a parameter in the call. The x is referring to the map that is to be added
in as a parameter, right? at least that is why I learned, when I studied
destructuring:
(def point {:x 5 :y 7})
>
> (let [{:keys [x y]} point]
> (println "x:" x "y:" y))
>
> => :x 5 :y 7
Does it work different different for defining function parameters? I posted
more under his comment above, please have a look.
Like you said, I also feel like I'm *starting* to get it and it is really
exciting :) Thanks for your advice.
Jesse
On Monday, May 12, 2014 7:46:34 PM UTC+9, David Della Costa wrote:
>
> > to reason about and can be dangerous. I would suggest putting
> > dynamically created channels in a collection inside an atom if you
> > need to create them like this.
>
> P.S. I just read James's response and I see he said something similar
> regarding this--it's better to structure this as a hash-map or other
> data structure, and use an atom if it needs to be updated dynamically.
> Notice that his code is far simpler and easier to reason about, and
> avoids the use of macros.
>
> DD
>
> (2014/05/12 19:40), Dave Della Costa wrote:
> >> I think I am confused about how to distinguish between a symbol and a
> >> variable, as I thought that the symbol being derefed pointed to the
> >> atom that it was made to define when transparent-chan was called.
> >
> > I think it's not so much that, as being mistaken about what is going at
> > compile-time vs. run-time in your macros. Going back to your original
> > code, your log-name function is just fine:
> >
> > (defn log-name [ch] (symbol (str ch '-log)))
> >
> > It returns a symbol, which is what you want for the second arg to def.
> >
> > However, keep in mind that this is going to return a list which will
> > then get evaluated, but it will only be the last value returned from
> 'do':
> >
> > (defmacro transparent-chan [ch]
> > (do
> > `(def ~ch (chan))
> > `(def (log-name ~ch) (atom []))
> > `(println "new transparent channel created!")))
> >
> > that is, a list like this:
> >
> > `(println "new transparent channel created!")
> >
> > ...which will then get evaluated at run-time. So your def calls will
> > never run! If we know that we can adjust it--
> >
> > (defmacro transparent-chan [ch]
> > `(do (def ~ch (async/chan))
> > (def (log-name ~ch) (atom []))
> > (println "new transparent channel created!")))
> >
> > ...but then we get:
> >
> > user=> (transparent-chan my-chan)
> >
> > CompilerException java.lang.RuntimeException: First argument to def must
> > be a Symbol, compiling... ; etc.
> > user=>
> >
> > Hmm...still a problem. Let's see, when is the 'log-name' function
> > getting run? Oh, at *run-time*...but we want it run at compile-time.
> > So, knowing that, we can adjust it again:
> >
> > (defmacro transparent-chan [ch]
> > `(do (def ~ch (async/chan))
> > (def ~(log-name ch) (atom []))
> > (println "new transparent channel created!")))
> >
> > Now we see:
> >
> > user=> (transparent-chan my-chan)
> > new transparent channel created!
> > nil
> > user=> my-chan
> > #<ManyToManyChannel
> > clojure.core.async.impl.channels.ManyToManyChannel@7b3287a>
> > user=> my-chan-log
> > #<Atom@49d869e7: []>
> > user=> my-chan-log
> >
> > Etc. I think that you need to keep playing with it and you'll get it; it
> > doesn't seem too far off.
> >
> > That said, if I were you I'd still try it the simpler way I proposed
> > before--this seems like a lot of work for not a lot of payoff, when you
> > can just dump out logging information at the time you send or receive a
> > message. And in general creating vars like this dynamically is not easy
> > to reason about and can be dangerous. I would suggest putting
> > dynamically created channels in a collection inside an atom if you need
> > to create them like this.
> >
> >> Later I was thinking about incorporating it into a gui to see
> >> if it's possible to design an asynchronous message passing system
> >> using drag and drop icons that represent pubs and subs, channels with
> >> a drop-down contents tab, and running listening processes.
> >> I know this is probably out of my league, but I was just asking
> >> myself how something like that might be implemented.
> >
> > I think it's totally possible and there's no reason it would be out of
> > your league. Just keep trying and asking questions here (and on IRC too
> > if you want to jump on, plenty of folks there willing to help out).
> >
> > DD
> >
> > (2014/05/12 17:26), gamma235 wrote:
> >> Thank you for your answer David.
> >>
> >> I think I am confused about how to distinguish between a symbol and a
> >> variable, as I thought that the symbol being derefed pointed to the
> atom
> >> that it was made to define when transparent-chan was called.
> >>
> >> Also, I am trying to specifically solve the logging problem to
> >> understand how I might use stored values or state outside the scope of
> >> the channel as a means of creating the illusion of referencing its
> >> contents. Later I was thinking about incorporating it into a gui to see
> >> if it's possible to design an asynchronous message passing system using
> >> drag and drop icons that represent pubs and subs, channels with a
> >> drop-down contents tab, and running listening processes. I know this is
> >> probably out of my league, but I was just asking myself how something
> >> like that might be implemented. I will of course continue to learn and
> >> reinforce the basics though on my own.
> >>
> >> Jesse
> >>
> >> On Monday, May 12, 2014 1:26:57 PM UTC+9, David Della Costa wrote:
> >>
> >> I apologize, apparently you can't use go-loop how I did below,
> >>
> >> => (def my-go-loop (async/go-loop [msg (async/<! c)] (println "got
> >> msg "
> >> msg " from channel " 'c)))
> >>
> >> ...try this instead:
> >>
> >> (def my-go-loop (async/go-loop [] (let [msg (async/<! c)] (println
> "got
> >> msg " msg " from channel " 'c))))
> >>
> >> Sorry about that!
> >>
> >> DD
> >>
> >> (2014/05/12 13:21), Dave Della Costa wrote:
> >> >
> >> >> 1) I feel like it is a redundant to define bindings multiple
> >> times in
> >> >> my go's let exprs when the params have already been passed in as
> >> >> arguments. Is there a more idiomatic way to do this?
> >> >
> >> > I think the fact that you are re-binding in a let should show you
> >> that
> >> > these variables are already in scope: that let is wholly
> >> redundant, just
> >> > remove it.
> >> >
> >> >
> >> >> 2) Whenever I try to create a generic process to automatically
> >> >> generate a log-name for each channel and then call update, I get
> a
> >> >> 'symbol cannot be cast to atom' error. How can I get around
> this? It
> >> >> seems to happen even if I don't use the log-name function.
> >> >
> >> > It's simple: a symbol is not an atom. It's telling you exactly
> >> what you
> >> > need to know: you cannot call swap! on a symbol. Make sure your
> >> atom is
> >> > the first argument to swap! wherever you use it.
> >> >
> >> >
> >> >> 3) Is there a better way to keep track of what's on a channel
> that
> >> >> doesn't use macros?
> >> >
> >> > You cannot look inside of a channel, but to do what you want and
> >> get a
> >> > sense of how core.async works, I think you are on the right track
> by
> >> > logging as you put stuff in and take it out.
> >> >
> >> > That said, I would start by getting rid of the log and the
> >> macro--these
> >> > are unnecessary complications--and do things very simply:
> >> >
> >> > => (require '[clojure.core.async :as async])
> >> > nil
> >> > => (def c (async/chan))
> >> > #'user/c
> >> > => (def my-go-loop (async/go-loop [msg (async/<! c)] (println
> "got
> >> msg "
> >> > msg " from channel " 'c)))
> >> > #'user/my-go-loop
> >> > => (defn put-and-print! [c msg] (println "putting msg " msg "
> onto
> >> > channel " 'c) (async/put! c msg))
> >> > #'user/put-and-print!
> >> > => (put-and-print! c "I am a message!")
> >> > putting msg I am a message! onto channel c
> >> > got msg I am a message! from channel c
> >> > nil
> >> > =>
> >> >
> >> > Printing out "channel c" is kind of silly since there is only
> one,
> >> but
> >> > it sounds like you may want to do this with multiple channels so
> >> this is
> >> > one way to print out the variable name--simply quote it.
> >> >
> >> > DD
> >> >
> >> > (2014/05/12 11:41), gamma235 wrote:
> >> >> Hi everyone,
> >> >>
> >> >> I am getting my feet wet with core.async and am trying to attach
> >> atoms
> >> >> to channels that update automatically and print out to the
> >> console as
> >> >> you take and put. This is not for anything serious, just a way
> to
> >> get
> >> >> familiar with the behavior and functionality of the library and
> >> practice
> >> >> my Clojure skills. Thanks in advaan
> >> >>
> >> >> Here is my code:
> >> >>
> >> >> (defn log-name [ch] (symbol (str ch '-log)))
> >> >>
> >> >> ;; Is this efficiently written?
> >> >> (defmacro transparent-chan [ch]
> >> >> (do
> >> >> `(def ~ch (chan))
> >> >> `(def (log-name ~ch) (atom []))
> >> >> `(println "new transparent channel created!")))
> >> >>
> >> >> (defn- update [log v]
> >> >> (do
> >> >> (swap! log conj v)
> >> >> (println "log test passed: " v " has been logged")
> >> >> (println "channel contents: " @log)))
> >> >>
> >> >> (defn transparent-put [ch v]
> >> >> (let [log (log-name ch)]
> >> >> (go
> >> >> (let [ch ch
> >> >> v v]
> >> >> (>! ch v)
> >> >> (println v " has been successfully moved through the
> >> channel")))
> >> >> (update log v)
> >> >> (println "put test passed: " v " has been put on the
> >> channel")
> >> >> (println " rechecking channel contents: " @log)))
> >> >>
> >> >> (defn transparent-take [ch]
> >> >> (go
> >> >> (let [v (<! ch)
> >> >> log-name (symbol (str ch '-log))]
> >> >> (swap! log-name #(remove #{v} %))
> >> >> (println v "has been removed from channel")))
> >> >> (println " removal pending"))
> >> >>
> >> >>
> >> >>
> >> >> ;; tests
> >> >> (transparent-chan c)
> >> >> c
> >> >> c-log
> >> >> @c-log
> >> >> (transparent-put c 42)
> >> >> (transparent-take c)
> >> >>
> >> >>
> >> >>
> >> >> My main questions are regarding variable scope:
> >> >> 1) I feel like it is a redundant to define bindings multiple
> >> times in my
> >> >> go's let exprs when the params have already been passed in as
> >> arguments.
> >> >> Is there a more idiomatic way to do this?
> >> >>
> >> >> 2) Whenever I try to create a generic process to automatically
> >> generate
> >> >> a log-name for each channel and then call update, I get a
> 'symbol
> >> cannot
> >> >> be cast to atom' error. How can I get around this? It seems to
> >> happen
> >> >> even if I don't use the log-name function.
> >> >>
> >> >> 3) Is there a better way to keep track of what's on a channel
> that
> >> >> doesn't use macros?
> >> >>
> >> >> --
> >> >> You received this message because you are subscribed to the
> Google
> >> >> Groups "Clojure" group.
> >> >> To post to this group, send email to [email protected]
> >> <javascript:>
> >> >> Note that posts from new members are moderated - please be
> >> patient with
> >> >> your first post.
> >> >> To unsubscribe from this group, send email to
> >> >> [email protected] <javascript:>
> >> >> For more options, visit this group at
> >> >> http://groups.google.com/group/clojure?hl=en
> >> <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 [email protected] <javascript:>
> >> >> <mailto:[email protected] <javascript:>>.
> >> >> For more options, visit https://groups.google.com/d/optout
> >> <https://groups.google.com/d/optout>.
> >>
> >> --
> >> You received this message because you are subscribed to the Google
> >> Groups "Clojure" group.
> >> To post to this group, send email to [email protected]<javascript:>
> >> Note that posts from new members are moderated - please be patient with
> >> your first post.
> >> To unsubscribe from this group, send email to
> >> [email protected] <javascript:>
> >> 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 [email protected] <javascript:>
> >> <mailto:[email protected] <javascript:>>.
> >> For more options, visit https://groups.google.com/d/optout.
>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/d/optout.