Core-async transducers with atoms
I have a question about transducers in core.async channels. As far as I understand, if I define a channel with a transducer, the latter cannot depend on any other external argument other than what is put on the former. So the transducer works in a purely functional fashion. Here is the question: is it idiomatic to define a transducer which depends (without side-effects) on a globally defined atom? Consider this example with a chatroom. Suppose we have a set (called banned-users) containing the names of users who have been banned from the chat. Let us initialize banned-users like this: (def banned-users (atom #{})) Let us further suppose that this set can change in time with users added and removed asynchronously. Every user can send messages to the server containing their name and the actual text of the message, in this format: {:name "John" :text "Hi, friends!"} Depending on whether the user is banned or not, the server will broadcast their message to all the other users or not. To this aim, let us define a channel with a transducer: (def server (chan 1 (filter #(not (contains? @banned-users (:name %) ) ))) As you can see, the effect of the transducer on the input message depends on the current value of banned-users. In other words, the channel does not work in a purely functional way, because given an input message, the result of applying the transducer will depend on the global context. Is this idiomatic or do you suggest other solutions? Thanks! -- 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/d/optout.
Re: Controlling how maps/records/atoms etc. are printed out
Thanks Timothy On Saturday, 12 November 2016, Timothy Baldridge wrote: > clojure.core/print-method is a multi method that handles the printing of > objects. You can override or implement the print method by: > > (defmethod print-method my.class.Foo > [^my.class.Foo instance ^Writer w] > (.write w ...)) > > I do that to provide custom printing for deftypes, but you can easily > override how records are printed as well. > > Timothy > > On Sat, Nov 12, 2016 at 2:35 AM, Colin Yates > wrote: > >> Hi all, >> >> I cache quite a bit of stuff on the server, so when I return or print >> out the 'system' I get the unhelpful recursive stack trace of Java >> running out of heap. >> >> Is there some protocol I can implement on large data structures such >> that whenever they are serialised they just dump some of their >> contents? >> >> These objects will only ever be printed out either at the REPL, >> (println) or clojure.tools.logging/log etc. I never expect them to be >> serialised and then later deserialised from the serialised form. >> >> Any suggestions? >> >> Thanks all, >> >> Colin >> >> -- >> 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/d/optout. >> > > > > -- > “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/d/optout. > -- 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/d/optout.
Re: Controlling how maps/records/atoms etc. are printed out
clojure.core/print-method is a multi method that handles the printing of objects. You can override or implement the print method by: (defmethod print-method my.class.Foo [^my.class.Foo instance ^Writer w] (.write w ...)) I do that to provide custom printing for deftypes, but you can easily override how records are printed as well. Timothy On Sat, Nov 12, 2016 at 2:35 AM, Colin Yates wrote: > Hi all, > > I cache quite a bit of stuff on the server, so when I return or print > out the 'system' I get the unhelpful recursive stack trace of Java > running out of heap. > > Is there some protocol I can implement on large data structures such > that whenever they are serialised they just dump some of their > contents? > > These objects will only ever be printed out either at the REPL, > (println) or clojure.tools.logging/log etc. I never expect them to be > serialised and then later deserialised from the serialised form. > > Any suggestions? > > Thanks all, > > Colin > > -- > 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/d/optout. > -- “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/d/optout.
Controlling how maps/records/atoms etc. are printed out
Hi all, I cache quite a bit of stuff on the server, so when I return or print out the 'system' I get the unhelpful recursive stack trace of Java running out of heap. Is there some protocol I can implement on large data structures such that whenever they are serialised they just dump some of their contents? These objects will only ever be printed out either at the REPL, (println) or clojure.tools.logging/log etc. I never expect them to be serialised and then later deserialised from the serialised form. Any suggestions? Thanks all, Colin -- 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/d/optout.
Re: atoms not working same in cljs as in clj?
On Fri, May 20, 2016 at 12:50 PM, Kevin Downey wrote: > This is a difference in the type function. The clojurescript type > function ignores metadata. Thanks! That was my second guess, but I looked and did not see that documented on the differences page. I already had an ia-type? function encapsulating the type check so I modified that to check the meta under cljs. -- Kenneth Tilton 54 Isle of Venice Dr, Apt 5 Fort Lauderdale, FL 33301 kentil...@gmail.com 646-269-1077 -- 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/d/optout.
Re: atoms not working same in cljs as in clj?
This is a difference in the type function. The clojurescript type function ignores metadata. So the clojurescript type function is like the clojure class function, and clojurescript doesn't have a class function. On 05/20/2016 09:22 AM, hiskennyness wrote: > I see here > https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure > that "Atoms work as in Clojure.", but I think I see a difference: > > 1. I am using a custom type hierarchy in a namespace > tiltontec.modeller.cell_types: > > | > (defonce ia-types (-> (make-hierarchy) > (derive ::model ::object) > (derive ::cell ::object) > (derive ::c-formula ::cell))) > > | > > 2. At the repl I switch to the cell types namespace and create an atom: > > | > (def my-formula (atom 42 :meta {:type ::c-formula})) > | > > 3. In Clojure: > > | > (type my-formula) => :tiltontec.modeller.cell-types/c-formula > | > > 4. In cljs: > > | > (type my-formula) => cljs.core.Atom > | > > Sanity check: > > | > (meta my-formula) => {:type :tiltontec.modeller.cell-types/c-formula} > | > > Am I missing something? > > -- > 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 > <mailto:clojure+unsubscr...@googlegroups.com>. > For more options, visit https://groups.google.com/d/optout. -- And what is good, Phaedrus, And what is not good— Need we ask anyone to tell us these things? -- 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/d/optout.
atoms not working same in cljs as in clj?
I see here https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure that "Atoms work as in Clojure.", but I think I see a difference: 1. I am using a custom type hierarchy in a namespace tiltontec.modeller.cell_types: (defonce ia-types (-> (make-hierarchy) (derive ::model ::object) (derive ::cell ::object) (derive ::c-formula ::cell))) 2. At the repl I switch to the cell types namespace and create an atom: (def my-formula (atom 42 :meta {:type ::c-formula})) 3. In Clojure: (type my-formula) => :tiltontec.modeller.cell-types/c-formula 4. In cljs: (type my-formula) => cljs.core.Atom Sanity check: (meta my-formula) => {:type :tiltontec.modeller.cell-types/c-formula} Am I missing something? -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
On Thursday, December 10, 2015 at 4:40:49 AM UTC-6, Dan Kersten wrote: > > I write such code like this: > > (defn sdescriptive-name [] ) > (def my-atom (atom (descriptive-name))) > > Where descriptive-name would describe the data shape or purpose. > This way the atom is not obscured behind many lines of code and the > data-generation is factored into a testable function with a hopefully > self-documenting name. > > On Thu, 10 Dec 2015 at 10:27 Colin Yates > > wrote: > >> I know it is dangerous to make sweeping statements, but any solution to >> “a lot of code obscures meaning therefore do X” is often solving the wrong >> thing - the real problem is "a lot of code that obscures meaning” :-). >> >> I hope that doesn’t come across as condescending as I fear... >> > How dare you. :-) No, feedback is always good. As a rule of thumb, I tend to agree, but there are tradeoffs. In this case the long string of let bindings are all similar, and are used to create an initial data structure that plays a central role in a simulation. Different simulations vary only by what's in this data structure. It's clearest to keep the bindings together in one place, and there's no reason to pollute the top level. Daniel's solution is a good one. I had the code set up that way at one point, and may go back to it. (Normally I store the data structure directly in a top-level variable, which is referenced only once at the beginning of simulation runs, and update the structure in a purely functional way. Because of interaction with another program in my current project, I now have to maintain the structure in a state variable that changes, so I've added the atom wrapper. Same kind of data structure as in the purely functional versions, though.) -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
I write such code like this: (defn sdescriptive-name [] ) (def my-atom (atom (descriptive-name))) Where descriptive-name would describe the data shape or purpose. This way the atom is not obscured behind many lines of code and the data-generation is factored into a testable function with a hopefully self-documenting name. On Thu, 10 Dec 2015 at 10:27 Colin Yates wrote: > I know it is dangerous to make sweeping statements, but any solution to “a > lot of code obscures meaning therefore do X” is often solving the wrong > thing - the real problem is "a lot of code that obscures meaning” :-). > > I hope that doesn’t come across as condescending as I fear... > > > On 10 Dec 2015, at 06:02, Mars0i wrote: > > Another use case, fwiw: > > (def my-atom > (let [... > > ...] > (atom ...))) > > A special naming convention for (e.g.) atoms makes it clear that what's > below the many lines of let bindings (and maybe comment lines, too) is > going to produce an atom; you don't have to read down and find the one line > that contains '(atom'. > > -- > 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/d/optout. > > > -- > 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/d/optout. > -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
I know it is dangerous to make sweeping statements, but any solution to “a lot of code obscures meaning therefore do X” is often solving the wrong thing - the real problem is "a lot of code that obscures meaning” :-). I hope that doesn’t come across as condescending as I fear... > On 10 Dec 2015, at 06:02, Mars0i wrote: > > Another use case, fwiw: > > (def my-atom > (let [... > > ...] > (atom ...))) > > A special naming convention for (e.g.) atoms makes it clear that what's below > the many lines of let bindings (and maybe comment lines, too) is going to > produce an atom; you don't have to read down and find the one line that > contains '(atom'. > > -- > 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 > <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 > <mailto:clojure+unsubscr...@googlegroups.com>. > 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 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
Another use case, fwiw: (def my-atom (let [... ...] (atom ...))) A special naming convention for (e.g.) atoms makes it clear that what's below the many lines of let bindings (and maybe comment lines, too) is going to produce an atom; you don't have to read down and find the one line that contains '(atom'. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
Sure - but if I saw a reference (no pun intended) to ‘shopping-cart’ I would expect that to be stateful. Fns which take something and return something else I tend to name `something->something-else`. In other words, I am unlikely to have a var whose name is a lower-case noun that isn’t state. It is interesting to me, now I think about it that I have seen a few syntactical style guides but no semantic style guides for Clojure. This question suggests we need one…. > On 7 Dec 2015, at 09:41, Mark Engelberg wrote: > > On the contrary, I find that when I have something in my app like a > shopping-cart, there are usually two flavors of functions. On the one hand, > there will be helper functions that take an immutable shopping-cart and > return a new immutable shopping-cart. But on the other hand, there will also > be a few functions that manipulate the actual stateful atom/ref containing > the immutable shopping-cart. > > I can see how some sort of convention might be handy to distinguish, at a > glance, whether a function takes the immutable or stateful version of > shopping-cart by some symbol in the name of the input. > > > On Mon, Dec 7, 2015 at 12:37 AM, Colin Yates <mailto:colin.ya...@gmail.com>> wrote: > +1. > > I haven’t done an extensive study, but I am sure all of my atoms’s stand out > from other fns/vars because the name makes it obvious. For example, > ‘shopping-cart’ can _only_ sensibly be state which can only be an atom. > > Having said that, if I had mixed refs and atoms then I might consider > splitting those, but in general I find it obvious and intuitive when looking > through past code which are atoms and which are fns/vars. > > Might just be me though :-). > >> On 7 Dec 2015, at 08:26, Daniel Kersten > <mailto:dkers...@gmail.com>> wrote: >> >> I personally don't like this. >> >> An atom won't suddenly change value without your knowledge because to get >> its value, you must use @ or deref (which should be a big warning that, yes, >> this value might change between calls to deref). >> >> Adding sigils, in my opinion, adds to the noise and makes it harder to read. >> I personally find sigils to be a noisy mistake in other languages (perl, php >> etc) and in my opinion you can get more benefit through a suitable naming >> convention such as a -state prefix, eg: foo-state >> >> I think, mainly my dislike for sigils is on variables and not so much on >> functions as I'm ok with foo? being a predicate and foo! being unsafe in >> STM. I think that's because they tell you useful meta information about what >> the function does, but to use a variable, I already have to know what data >> it's representing in order to call the correct functions on it and >> annotating it with sigils doesn't help much (unless perhaps you go full >> blown Hungarian notation, but even that isn't rich enough to adequately >> describe the nested data structures we use in Clojure - good descriptive >> variable names are much better at conveying content and purpose). >> >> I guess it may largely just be personal taste, although I would also take >> the wider community into account: there's a lot of code out there not using >> this convention - will that become confusing if you rely on symbols to tell >> you that a variable is an atom? >> On Mon 7 Dec 2015 at 00:27 Mars0i > <mailto:marsh...@logical.net>> wrote: >> On Sunday, December 6, 2015 at 5:52:02 PM UTC-6, Glen Mailer wrote: >> I saw some sample code that prefixed the atom name with a ! recently, seemed >> to look sensible to me. >> (swap! !state conj :whatever) >> >> And so on. >> >> >> This idea is conceptually elegant, since the marker, !, is the same as the >> related function suffix. >> >> I worry that having two bangs with a space between them, as in the swap! >> example above, is a little bit visually confusing. Also, I wonder whether >> placing @ next two another non-alphanumeric character is visually confusing >> or messy. >> >> As an experiment, I just started using & as a suffix for variables whose >> values are atoms.: >> (def state& (atom 1)) >> (swap! state& inc) >> @state& >> >> Using only a suffix character means that you don't have a punctuation >> character next to @, which I prefer. >> >> (I wouldn't want to use ! as the suffix for variables that are not >> functions, though. (swap! state! inc) potentially very confusing. It's not >> that someone reading
Re: Naming convention for atoms, refs, etc.?
On the contrary, I find that when I have something in my app like a shopping-cart, there are usually two flavors of functions. On the one hand, there will be helper functions that take an immutable shopping-cart and return a new immutable shopping-cart. But on the other hand, there will also be a few functions that manipulate the actual stateful atom/ref containing the immutable shopping-cart. I can see how some sort of convention might be handy to distinguish, at a glance, whether a function takes the immutable or stateful version of shopping-cart by some symbol in the name of the input. On Mon, Dec 7, 2015 at 12:37 AM, Colin Yates wrote: > +1. > > I haven’t done an extensive study, but I am sure all of my atoms’s stand > out from other fns/vars because the name makes it obvious. For example, > ‘shopping-cart’ can _only_ sensibly be state which can only be an atom. > > Having said that, if I had mixed refs and atoms then I might consider > splitting those, but in general I find it obvious and intuitive when > looking through past code which are atoms and which are fns/vars. > > Might just be me though :-). > > On 7 Dec 2015, at 08:26, Daniel Kersten wrote: > > I personally don't like this. > > An atom won't suddenly change value without your knowledge because to get > its value, you must use @ or deref (which should be a big warning that, > yes, this value might change between calls to deref). > > Adding sigils, in my opinion, adds to the noise and makes it harder to > read. I personally find sigils to be a noisy mistake in other languages > (perl, php etc) and in my opinion you can get more benefit through a > suitable naming convention such as a -state prefix, eg: foo-state > > I think, mainly my dislike for sigils is on variables and not so much on > functions as I'm ok with foo? being a predicate and foo! being unsafe in > STM. I think that's because they tell you useful meta information about > what the function does, but to use a variable, I already have to know what > data it's representing in order to call the correct functions on it and > annotating it with sigils doesn't help much (unless perhaps you go full > blown Hungarian notation, but even that isn't rich enough to adequately > describe the nested data structures we use in Clojure - good descriptive > variable names are much better at conveying content and purpose). > > I guess it may largely just be personal taste, although I would also take > the wider community into account: there's a lot of code out there not using > this convention - will that become confusing if you rely on symbols to tell > you that a variable is an atom? > On Mon 7 Dec 2015 at 00:27 Mars0i wrote: > >> On Sunday, December 6, 2015 at 5:52:02 PM UTC-6, Glen Mailer wrote: >>> >>> I saw some sample code that prefixed the atom name with a ! recently, >>> seemed to look sensible to me. >>> >>> (swap! !state conj :whatever) >>> >>> And so on. >>> >> >> This idea is conceptually elegant, since the marker, !, is the same as >> the related function suffix. >> >> I worry that having two bangs with a space between them, as in the swap! >> example above, is a little bit visually confusing. Also, I wonder whether >> placing @ next two another non-alphanumeric character is visually confusing >> or messy. >> >> As an experiment, I just started using & as a suffix for variables whose >> values are atoms.: >> (def state& (atom 1)) >> (swap! state& inc) >> @state& >> >> Using only a suffix character means that you don't have a punctuation >> character next to @, which I prefer. >> >> (I wouldn't want to use ! as the suffix for variables that are not >> functions, though. (swap! state! inc) potentially very confusing. It's >> not that someone reading it couldn't figure it out, but if I saw that, I'd >> have to think for a second, and then keep remembering that state! is not a >> function.) >> >> It occurred to me that I've seen both & and $ used in some languages to >> suggest pointer dereferencing, so there's some vague harmony to using one >> of them as indicators as markers of statefulness. "Ampersand" sounds >> vaguely like "atom". If one wanted to have separate marker characters for >> atoms, refs, and agents, maybe & is a good choice for atoms. Not sure it's >> necessary to have different conventions for these three distinct uses, >> though. >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clo
Re: Naming convention for atoms, refs, etc.?
Good point, Colin, about mixed refs and atoms. That might change things a little (although in my years of Clojure, I have never needed to mix them to the point of needing to clarify). I would still prefer a textually descriptive name over a symbolic prefix or suffix in this case though. At the very least, something like foo-atom or foo-ref would be clear to people not used to the convention, while foo& could mean anything. I think usually one can come up with better descriptions than -atom too. But... Maybe I'm just a little bit too symbol averse 🤔😏 On Mon 7 Dec 2015 at 08:37 Colin Yates wrote: > +1. > > I haven’t done an extensive study, but I am sure all of my atoms’s stand > out from other fns/vars because the name makes it obvious. For example, > ‘shopping-cart’ can _only_ sensibly be state which can only be an atom. > > Having said that, if I had mixed refs and atoms then I might consider > splitting those, but in general I find it obvious and intuitive when > looking through past code which are atoms and which are fns/vars. > > Might just be me though :-). > > On 7 Dec 2015, at 08:26, Daniel Kersten wrote: > > I personally don't like this. > > An atom won't suddenly change value without your knowledge because to get > its value, you must use @ or deref (which should be a big warning that, > yes, this value might change between calls to deref). > > Adding sigils, in my opinion, adds to the noise and makes it harder to > read. I personally find sigils to be a noisy mistake in other languages > (perl, php etc) and in my opinion you can get more benefit through a > suitable naming convention such as a -state prefix, eg: foo-state > > I think, mainly my dislike for sigils is on variables and not so much on > functions as I'm ok with foo? being a predicate and foo! being unsafe in > STM. I think that's because they tell you useful meta information about > what the function does, but to use a variable, I already have to know what > data it's representing in order to call the correct functions on it and > annotating it with sigils doesn't help much (unless perhaps you go full > blown Hungarian notation, but even that isn't rich enough to adequately > describe the nested data structures we use in Clojure - good descriptive > variable names are much better at conveying content and purpose). > > I guess it may largely just be personal taste, although I would also take > the wider community into account: there's a lot of code out there not using > this convention - will that become confusing if you rely on symbols to tell > you that a variable is an atom? > On Mon 7 Dec 2015 at 00:27 Mars0i wrote: > >> On Sunday, December 6, 2015 at 5:52:02 PM UTC-6, Glen Mailer wrote: >>> >>> I saw some sample code that prefixed the atom name with a ! recently, >>> seemed to look sensible to me. >>> >>> (swap! !state conj :whatever) >>> >>> And so on. >>> >> >> This idea is conceptually elegant, since the marker, !, is the same as >> the related function suffix. >> >> I worry that having two bangs with a space between them, as in the swap! >> example above, is a little bit visually confusing. Also, I wonder whether >> placing @ next two another non-alphanumeric character is visually confusing >> or messy. >> >> As an experiment, I just started using & as a suffix for variables whose >> values are atoms.: >> (def state& (atom 1)) >> (swap! state& inc) >> @state& >> >> Using only a suffix character means that you don't have a punctuation >> character next to @, which I prefer. >> >> (I wouldn't want to use ! as the suffix for variables that are not >> functions, though. (swap! state! inc) potentially very confusing. It's >> not that someone reading it couldn't figure it out, but if I saw that, I'd >> have to think for a second, and then keep remembering that state! is not a >> function.) >> >> It occurred to me that I've seen both & and $ used in some languages to >> suggest pointer dereferencing, so there's some vague harmony to using one >> of them as indicators as markers of statefulness. "Ampersand" sounds >> vaguely like "atom". If one wanted to have separate marker characters for >> atoms, refs, and agents, maybe & is a good choice for atoms. Not sure it's >> necessary to have different conventions for these three distinct uses, >> though. >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to t
Re: Naming convention for atoms, refs, etc.?
+1. I haven’t done an extensive study, but I am sure all of my atoms’s stand out from other fns/vars because the name makes it obvious. For example, ‘shopping-cart’ can _only_ sensibly be state which can only be an atom. Having said that, if I had mixed refs and atoms then I might consider splitting those, but in general I find it obvious and intuitive when looking through past code which are atoms and which are fns/vars. Might just be me though :-). > On 7 Dec 2015, at 08:26, Daniel Kersten wrote: > > I personally don't like this. > > An atom won't suddenly change value without your knowledge because to get its > value, you must use @ or deref (which should be a big warning that, yes, this > value might change between calls to deref). > > Adding sigils, in my opinion, adds to the noise and makes it harder to read. > I personally find sigils to be a noisy mistake in other languages (perl, php > etc) and in my opinion you can get more benefit through a suitable naming > convention such as a -state prefix, eg: foo-state > > I think, mainly my dislike for sigils is on variables and not so much on > functions as I'm ok with foo? being a predicate and foo! being unsafe in STM. > I think that's because they tell you useful meta information about what the > function does, but to use a variable, I already have to know what data it's > representing in order to call the correct functions on it and annotating it > with sigils doesn't help much (unless perhaps you go full blown Hungarian > notation, but even that isn't rich enough to adequately describe the nested > data structures we use in Clojure - good descriptive variable names are much > better at conveying content and purpose). > > I guess it may largely just be personal taste, although I would also take the > wider community into account: there's a lot of code out there not using this > convention - will that become confusing if you rely on symbols to tell you > that a variable is an atom? > On Mon 7 Dec 2015 at 00:27 Mars0i <mailto:marsh...@logical.net>> wrote: > On Sunday, December 6, 2015 at 5:52:02 PM UTC-6, Glen Mailer wrote: > I saw some sample code that prefixed the atom name with a ! recently, seemed > to look sensible to me. > (swap! !state conj :whatever) > > And so on. > > > This idea is conceptually elegant, since the marker, !, is the same as the > related function suffix. > > I worry that having two bangs with a space between them, as in the swap! > example above, is a little bit visually confusing. Also, I wonder whether > placing @ next two another non-alphanumeric character is visually confusing > or messy. > > As an experiment, I just started using & as a suffix for variables whose > values are atoms.: > (def state& (atom 1)) > (swap! state& inc) > @state& > > Using only a suffix character means that you don't have a punctuation > character next to @, which I prefer. > > (I wouldn't want to use ! as the suffix for variables that are not functions, > though. (swap! state! inc) potentially very confusing. It's not that > someone reading it couldn't figure it out, but if I saw that, I'd have to > think for a second, and then keep remembering that state! is not a function.) > > It occurred to me that I've seen both & and $ used in some languages to > suggest pointer dereferencing, so there's some vague harmony to using one of > them as indicators as markers of statefulness. "Ampersand" sounds vaguely > like "atom". If one wanted to have separate marker characters for atoms, > refs, and agents, maybe & is a good choice for atoms. Not sure it's > necessary to have different conventions for these three distinct uses, though. > > -- > 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 > <mailto: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 > <mailto:clojure%2bunsubscr...@googlegroups.com> > 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 clojure+unsubscr...@googlegroups.com > <mailto:clojure+unsubscr...@googlegroups.c
Re: Naming convention for atoms, refs, etc.?
I personally don't like this. An atom won't suddenly change value without your knowledge because to get its value, you must use @ or deref (which should be a big warning that, yes, this value might change between calls to deref). Adding sigils, in my opinion, adds to the noise and makes it harder to read. I personally find sigils to be a noisy mistake in other languages (perl, php etc) and in my opinion you can get more benefit through a suitable naming convention such as a -state prefix, eg: foo-state I think, mainly my dislike for sigils is on variables and not so much on functions as I'm ok with foo? being a predicate and foo! being unsafe in STM. I think that's because they tell you useful meta information about what the function does, but to use a variable, I already have to know what data it's representing in order to call the correct functions on it and annotating it with sigils doesn't help much (unless perhaps you go full blown Hungarian notation, but even that isn't rich enough to adequately describe the nested data structures we use in Clojure - good descriptive variable names are much better at conveying content and purpose). I guess it may largely just be personal taste, although I would also take the wider community into account: there's a lot of code out there not using this convention - will that become confusing if you rely on symbols to tell you that a variable is an atom? On Mon 7 Dec 2015 at 00:27 Mars0i wrote: > On Sunday, December 6, 2015 at 5:52:02 PM UTC-6, Glen Mailer wrote: >> >> I saw some sample code that prefixed the atom name with a ! recently, >> seemed to look sensible to me. >> >> (swap! !state conj :whatever) >> >> And so on. >> > > This idea is conceptually elegant, since the marker, !, is the same as the > related function suffix. > > I worry that having two bangs with a space between them, as in the swap! > example above, is a little bit visually confusing. Also, I wonder whether > placing @ next two another non-alphanumeric character is visually confusing > or messy. > > As an experiment, I just started using & as a suffix for variables whose > values are atoms.: > (def state& (atom 1)) > (swap! state& inc) > @state& > > Using only a suffix character means that you don't have a punctuation > character next to @, which I prefer. > > (I wouldn't want to use ! as the suffix for variables that are not > functions, though. (swap! state! inc) potentially very confusing. It's > not that someone reading it couldn't figure it out, but if I saw that, I'd > have to think for a second, and then keep remembering that state! is not a > function.) > > It occurred to me that I've seen both & and $ used in some languages to > suggest pointer dereferencing, so there's some vague harmony to using one > of them as indicators as markers of statefulness. "Ampersand" sounds > vaguely like "atom". If one wanted to have separate marker characters for > atoms, refs, and agents, maybe & is a good choice for atoms. Not sure it's > necessary to have different conventions for these three distinct uses, > though. > > -- > 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/d/optout. > -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
On Sunday, December 6, 2015 at 5:52:02 PM UTC-6, Glen Mailer wrote: > > I saw some sample code that prefixed the atom name with a ! recently, > seemed to look sensible to me. > > (swap! !state conj :whatever) > > And so on. > This idea is conceptually elegant, since the marker, !, is the same as the related function suffix. I worry that having two bangs with a space between them, as in the swap! example above, is a little bit visually confusing. Also, I wonder whether placing @ next two another non-alphanumeric character is visually confusing or messy. As an experiment, I just started using & as a suffix for variables whose values are atoms.: (def state& (atom 1)) (swap! state& inc) @state& Using only a suffix character means that you don't have a punctuation character next to @, which I prefer. (I wouldn't want to use ! as the suffix for variables that are not functions, though. (swap! state! inc) potentially very confusing. It's not that someone reading it couldn't figure it out, but if I saw that, I'd have to think for a second, and then keep remembering that state! is not a function.) It occurred to me that I've seen both & and $ used in some languages to suggest pointer dereferencing, so there's some vague harmony to using one of them as indicators as markers of statefulness. "Ampersand" sounds vaguely like "atom". If one wanted to have separate marker characters for atoms, refs, and agents, maybe & is a good choice for atoms. Not sure it's necessary to have different conventions for these three distinct uses, though. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
I saw some sample code that prefixed the atom name with a ! recently, seemed to look sensible to me. (swap! !state conj :whatever) And so on. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
I seriously doubt that's ever going to happen. There's no good reason to do that. > On 6 Dec 2015, at 21:00, Gregg Reynolds wrote: > > > On Dec 6, 2015 2:45 PM, "Nicola Mometto" wrote: > > > > 'foo@ is not a valid symbol name > > Oops. Maybe now is the time to make good on "other characters may be allowed > eventually" (from the Reader doc.) I can't think of a good reason not to > allow @ in symbols. Would it mess anything up? > > > > On 6 Dec 2015, at 20:44, Gregg Reynolds wrote: > > > > > > Ps. Note the nice symmetry between *foo* and @foo@. > > > > > > On Dec 6, 2015 2:42 PM, "Gregg Reynolds" wrote: > > > Postfix @? Haven't pondered this before but I like the idea. Why should > > > perl have all the fun? > > > > > > On Dec 5, 2015 3:47 PM, "Mars0i" wrote: > > > &, $, and ! might be good to use as special naming characters for > > > atoms/refs/agents, either as an initial char, a final char, or both, but > > > I'm wondering whether anyone already has a naming convention that they > > > use. > > > > > > -- > > > 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/d/optout. > > > > > > -- > > > 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/d/optout. > > > > -- > > 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/d/optout. > > -- > 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/d/optout. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
On Dec 6, 2015 2:45 PM, "Nicola Mometto" wrote: > > 'foo@ is not a valid symbol name Oops. Maybe now is the time to make good on "other characters may be allowed eventually" (from the Reader doc.) I can't think of a good reason not to allow @ in symbols. Would it mess anything up? > > On 6 Dec 2015, at 20:44, Gregg Reynolds wrote: > > > > Ps. Note the nice symmetry between *foo* and @foo@. > > > > On Dec 6, 2015 2:42 PM, "Gregg Reynolds" wrote: > > Postfix @? Haven't pondered this before but I like the idea. Why should perl have all the fun? > > > > On Dec 5, 2015 3:47 PM, "Mars0i" wrote: > > &, $, and ! might be good to use as special naming characters for atoms/refs/agents, either as an initial char, a final char, or both, but I'm wondering whether anyone already has a naming convention that they use. > > > > -- > > 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/d/optout. > > > > -- > > 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/d/optout. > > -- > 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/d/optout. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
'foo@ is not a valid symbol name > On 6 Dec 2015, at 20:44, Gregg Reynolds wrote: > > Ps. Note the nice symmetry between *foo* and @foo@. > > On Dec 6, 2015 2:42 PM, "Gregg Reynolds" wrote: > Postfix @? Haven't pondered this before but I like the idea. Why should > perl have all the fun? > > On Dec 5, 2015 3:47 PM, "Mars0i" wrote: > &, $, and ! might be good to use as special naming characters for > atoms/refs/agents, either as an initial char, a final char, or both, but I'm > wondering whether anyone already has a naming convention that they use. > > -- > 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/d/optout. > > -- > 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/d/optout. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
Ps. Note the nice symmetry between *foo* and @foo@. On Dec 6, 2015 2:42 PM, "Gregg Reynolds" wrote: > Postfix @? Haven't pondered this before but I like the idea. Why should > perl have all the fun? > On Dec 5, 2015 3:47 PM, "Mars0i" wrote: > >> &, $, and ! might be good to use as special naming characters for >> atoms/refs/agents, either as an initial char, a final char, or both, but >> I'm wondering whether anyone already has a naming convention that they use. >> >> -- >> 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/d/optout. >> > -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
Postfix @? Haven't pondered this before but I like the idea. Why should perl have all the fun? On Dec 5, 2015 3:47 PM, "Mars0i" wrote: > &, $, and ! might be good to use as special naming characters for > atoms/refs/agents, either as an initial char, a final char, or both, but > I'm wondering whether anyone already has a naming convention that they use. > > -- > 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/d/optout. > -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
On Saturday, December 5, 2015 at 8:04:34 PM UTC-6, tbc++ wrote: > > Also, if you have so many atoms in your program that it becomes hard to > remember where they are, that would be another source of concern ;-) > Yeah I'm worried that I'll come back to the code a year later and not remember that the variable contains an atom, and wonder why I'm getting different things out of it. Though I suppose the at-sign might be a tip-off. Or suppose I have a recurrent role in several functions or several namespaces or several programs, for which I always use the same name. Using the same name in different contexts makes the meaning of the variables clear. Then it turns out that I have to make a new special version of this kind of program, in which I need to store the same kind of data in an atom rather than simply passing it from function to function. I want to give the variable containing the data the same name ... but I don't, because this variable is different--it contains an atom containing the usual data, rather than the data itself. (This is actually the situation that prompted the question. I don't like having to store the data in an atom, but ) -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
On Saturday, December 5, 2015 at 5:45:22 PM UTC-6, James Reeves wrote: > > Why should they have any sort of naming scheme? Dynamic vars are unusual > because their values can change. Atoms and refs remain the same, and even > though inside their values mutate, they don't affect the outer var. > Good point, James. They're just regular variables. Still, their role is very different from that of normal Clojure variables. I prefer to give them a different kind of name. But I can understand why others wouldn't. -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
Also, if you have so many atoms in your program that it becomes hard to remember where they are, that would be another source of concern ;-) On Sat, Dec 5, 2015 at 4:44 PM, James Reeves wrote: > Why should they have any sort of naming scheme? Dynamic vars are unusual > because their values can change. Atoms and refs remain the same, and even > though inside their values mutate, they don't affect the outer var. > > - James > > On 5 December 2015 at 21:39, Mars0i wrote: > >> Does anyone want to suggest or promote a naming convention for atoms, >> refs, and agents, i.e. some of things that you can dereference with @ i.e. >> deref? >> >> (Also, what about futures, delays, and promises? I think of these as >> playing a different sort of role, even though deref works with them, too.) >> >> The Clojure style guide >> <https://github.com/bbatsov/clojure-style-guide#naming> says: >> >> Use *earmuffs* for things intended for rebinding (ie. are dynamic). >> >> ;; good >> (def ^:dynamic *a* 10) >> >> >> It could be reasonable to use earmuffs for atoms, etc., too, but I think >> that "@*my-atom*" is ugly because of the juxtaposed @-sign and asterisk, >> and in any event I think of rebinding as a different kind of thing from >> what happens with atoms/refs/agents. >> >> -- >> 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/d/optout. >> > > -- > 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/d/optout. > -- “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/d/optout.
Re: Naming convention for atoms, refs, etc.?
Why should they have any sort of naming scheme? Dynamic vars are unusual because their values can change. Atoms and refs remain the same, and even though inside their values mutate, they don't affect the outer var. - James On 5 December 2015 at 21:39, Mars0i wrote: > Does anyone want to suggest or promote a naming convention for atoms, > refs, and agents, i.e. some of things that you can dereference with @ i.e. > deref? > > (Also, what about futures, delays, and promises? I think of these as > playing a different sort of role, even though deref works with them, too.) > > The Clojure style guide > <https://github.com/bbatsov/clojure-style-guide#naming> says: > > Use *earmuffs* for things intended for rebinding (ie. are dynamic). > > ;; good > (def ^:dynamic *a* 10) > > > It could be reasonable to use earmuffs for atoms, etc., too, but I think > that "@*my-atom*" is ugly because of the juxtaposed @-sign and asterisk, > and in any event I think of rebinding as a different kind of thing from > what happens with atoms/refs/agents. > > -- > 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/d/optout. > -- 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/d/optout.
Re: Naming convention for atoms, refs, etc.?
&, $, and ! might be good to use as special naming characters for atoms/refs/agents, either as an initial char, a final char, or both, but I'm wondering whether anyone already has a naming convention that they use. -- 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/d/optout.
Naming convention for atoms, refs, etc.?
Does anyone want to suggest or promote a naming convention for atoms, refs, and agents, i.e. some of things that you can dereference with @ i.e. deref? (Also, what about futures, delays, and promises? I think of these as playing a different sort of role, even though deref works with them, too.) The Clojure style guide <https://github.com/bbatsov/clojure-style-guide#naming> says: Use *earmuffs* for things intended for rebinding (ie. are dynamic). ;; good (def ^:dynamic *a* 10) It could be reasonable to use earmuffs for atoms, etc., too, but I think that "@*my-atom*" is ugly because of the juxtaposed @-sign and asterisk, and in any event I think of rebinding as a different kind of thing from what happens with atoms/refs/agents. -- 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/d/optout.
Re: Atoms, reference to itself cause StackOverflowError
Thank you :) Extremely clear ! On Friday, August 7, 2015 at 3:48:14 PM UTC+2, Stuart Sierra wrote: > > Hi Simone, > > The stack overflow here is caused by the REPL trying to print a circular > reference. `swap!` always returns the new value of the Atom, and the REPL > tries to print it. > > If you don't print the Atom, this self-reference can still work: > > user=> (def a (atom {})) > #'user/a > user=> (do (swap! a assoc :self a) nil) > nil > user=> (= a (:self @a)) > true > > –S > > > On Friday, August 7, 2015 at 9:42:05 AM UTC-4, Simone Mosciatti wrote: >> >> Hi all, >> >> I noticed this behaviour that I was not expecting: >> >> simo@simo:~$ lein repl >> nREPL server started on port 42010 on host 127.0.0.1 - nrepl:// >> 127.0.0.1:42010 >> REPL-y 0.3.5, nREPL 0.2.6 >> Clojure 1.6.0 >> OpenJDK 64-Bit Server VM 1.7.0_79-b14 >> Docs: (doc function-name-here) >> (find-doc "part-of-name-here") >> Source: (source function-name-here) >> Javadoc: (javadoc java-object-or-class-here) >> Exit: Control+D or (exit) or (quit) >> Results: Stored in vars *1, *2, *3, an exception in *e >> >> user=> (def a (atom {})) >> #'user/a >> user=> (swap! a assoc :self a) >> >> StackOverflowError java.util.regex.Pattern$GroupHead.match >> (Pattern.java:4556) >> user=> (swap! a assoc :test :ok) >> >> StackOverflowError java.lang.Character.codePointAt (Character.java:4668) >> user=> a >> >> StackOverflowError java.util.regex.Pattern$Curly.match0 >> (Pattern.java:4148) >> user=> (def b (atom {})) >> #'user/b >> user=> (swap! b assoc :test :ok) >> {:test :ok} >> >> It is something expected or I should open a bug report ? >> >> Greets >> >> Simone >> > -- 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/d/optout.
Re: Atoms, reference to itself cause StackOverflowError
Hi Simone, The stack overflow here is caused by the REPL trying to print a circular reference. `swap!` always returns the new value of the Atom, and the REPL tries to print it. If you don't print the Atom, this self-reference can still work: user=> (def a (atom {})) #'user/a user=> (do (swap! a assoc :self a) nil) nil user=> (= a (:self @a)) true –S On Friday, August 7, 2015 at 9:42:05 AM UTC-4, Simone Mosciatti wrote: > > Hi all, > > I noticed this behaviour that I was not expecting: > > simo@simo:~$ lein repl > nREPL server started on port 42010 on host 127.0.0.1 - nrepl:// > 127.0.0.1:42010 > REPL-y 0.3.5, nREPL 0.2.6 > Clojure 1.6.0 > OpenJDK 64-Bit Server VM 1.7.0_79-b14 > Docs: (doc function-name-here) > (find-doc "part-of-name-here") > Source: (source function-name-here) > Javadoc: (javadoc java-object-or-class-here) > Exit: Control+D or (exit) or (quit) > Results: Stored in vars *1, *2, *3, an exception in *e > > user=> (def a (atom {})) > #'user/a > user=> (swap! a assoc :self a) > > StackOverflowError java.util.regex.Pattern$GroupHead.match > (Pattern.java:4556) > user=> (swap! a assoc :test :ok) > > StackOverflowError java.lang.Character.codePointAt (Character.java:4668) > user=> a > > StackOverflowError java.util.regex.Pattern$Curly.match0 > (Pattern.java:4148) > user=> (def b (atom {})) > #'user/b > user=> (swap! b assoc :test :ok) > {:test :ok} > > It is something expected or I should open a bug report ? > > Greets > > Simone > -- 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/d/optout.
Atoms, reference to itself cause StackOverflowError
Hi all, I noticed this behaviour that I was not expecting: simo@simo:~$ lein repl nREPL server started on port 42010 on host 127.0.0.1 - nrepl://127.0.0.1:42010 REPL-y 0.3.5, nREPL 0.2.6 Clojure 1.6.0 OpenJDK 64-Bit Server VM 1.7.0_79-b14 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e user=> (def a (atom {})) #'user/a user=> (swap! a assoc :self a) StackOverflowError java.util.regex.Pattern$GroupHead.match (Pattern.java:4556) user=> (swap! a assoc :test :ok) StackOverflowError java.lang.Character.codePointAt (Character.java:4668) user=> a StackOverflowError java.util.regex.Pattern$Curly.match0 (Pattern.java:4148) user=> (def b (atom {})) #'user/b user=> (swap! b assoc :test :ok) {:test :ok} It is something expected or I should open a bug report ? Greets Simone -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
Hi, Thanks for all suggestions. It all encouraged me to deep dive into atom-s code which turns out to be a simple wrapper over Java java.util.concurrent.atomic.AtomicReference which essentially is a spinlock. Knowing how it works under the hood makes so easier to use it ... Below piece (hopefully correct) let me update map atomically: (defn cond-assoc! [atomic-map key val] (loop [] (let [candidate (if (contains? @atomic-map key) @atomic-map (assoc @atomic-map key val))] (if (compare-and-set! atomic-map @atomic-map candidate) candidate (recur) I also learned that using future (or essentially Java threads) is so poor approach to scalability. derefing memoized delay of my function wrapped with future worked well to some point. After pushing it a bit with more concurrent tasks, my JVM started freezing under pressure of to many threads. I ended up with my custom hybrid of a queued future-s. I have also a version done in core.async - I will try to write it up in a separate piece at some point .. Best regards, Andy -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
On 8 December 2014 at 21:46, Fluid Dynamics wrote: > [...] > Which means it's locking or bust. You just get to either do the locking > yourself or delegate :) Sure, but isn't it nice when somebody else does your locking for you? :-) Incidentally, there is a trade-off here between lockless reads and cache-locking writes in the version with (locking …) and synchronized reads (of delays) and somewhat concurrency-friendly writes in the version with CHM.putIfAbsent and delays. So actually explicit (locking …) might be preferable for certain workloads. Benchmarking required. Michał > > -- > 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/d/optout. -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
Oh, and as for how to use it here, you could for example say (.putIfAbsent concurrent-hash-map :foo (delay (foo))) Then the first thread to @(get concurrent-hash-map :foo (delay :not-found)) (or similar) would actually compute the value. With a map in an atom, you could swap! using a function like (fn [old-state] (if (contains? old-state :foo) (assoc old-state :foo (delay (foo))) old-state)) I'd probably prefer a CHM for this purpose, though. Michał On 8 December 2014 at 21:33, Michał Marczyk wrote: > On 8 December 2014 at 17:54, Andy L wrote: >>> But I'd personally just use a delay rather than "locking" for this >>> purpose. >> >> >> It is not that I like locking at all. However I still fail to see, how in a >> multithreaded context memoize/cache prevents executing a given function more >> than once (which I want to avoid at any cost here) since cache lookup and >> swap! does not seem to be atomic : >> https://github.com/clojure/core.cache/blob/master/src/main/clojure/clojure/core/cache.clj#L52 > > When you say > > (delay (foo)), > > foo will be called at most once, regardless of how many times you > deref (@) / force the delay. (If you never force the delay, it will > not be called at all.) The way this is enforced is through making > deref a synchronized method on delays. > > Cheers, > Michał -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
On Monday, December 8, 2014 3:34:05 PM UTC-5, Michał Marczyk wrote: > > On 8 December 2014 at 17:54, Andy L > > wrote: > >> But I'd personally just use a delay rather than "locking" for this > >> purpose. > > > > > > It is not that I like locking at all. However I still fail to see, how > in a > > multithreaded context memoize/cache prevents executing a given function > more > > than once (which I want to avoid at any cost here) since cache lookup > and > > swap! does not seem to be atomic : > > > https://github.com/clojure/core.cache/blob/master/src/main/clojure/clojure/core/cache.clj#L52 > > > When you say > > (delay (foo)), > > foo will be called at most once, regardless of how many times you > deref (@) / force the delay. (If you never force the delay, it will > not be called at all.) The way this is enforced is through making > deref a synchronized method on delays. > Which means it's locking or bust. You just get to either do the locking yourself or delegate :) -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
On 8 December 2014 at 17:54, Andy L wrote: >> But I'd personally just use a delay rather than "locking" for this >> purpose. > > > It is not that I like locking at all. However I still fail to see, how in a > multithreaded context memoize/cache prevents executing a given function more > than once (which I want to avoid at any cost here) since cache lookup and > swap! does not seem to be atomic : > https://github.com/clojure/core.cache/blob/master/src/main/clojure/clojure/core/cache.clj#L52 When you say (delay (foo)), foo will be called at most once, regardless of how many times you deref (@) / force the delay. (If you never force the delay, it will not be called at all.) The way this is enforced is through making deref a synchronized method on delays. Cheers, Michał -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
> > > Most of the cache implementations in core.cache have no side-effects. They > simply return a new cache rather than overwriting the old one. The memoize > library places the cache in an atom, so it's guaranteed to change > atomically. > I tried to read the cache code (btw an excellent exercise) , and I think I understand how persistent data structure/atom is employed here in case we deal with side effects free functions. > You could write this as a function. There's nothing in there that requires > a macro. > > (defn when-map-future-swap! [a k f] > (locking a > (when-not (contains? @a k) > (swap! a assoc k nil) > (future (swap! a assoc k (f k)) > I realized that later too ... But I'd personally just use a delay rather than "locking" for this purpose. > It is not that I like locking at all. However I still fail to see, how in a multithreaded context memoize/cache prevents executing a given function more than once (which I want to avoid at any cost here) since cache lookup and swap! does not seem to be atomic : https://github.com/clojure/core.cache/blob/master/src/main/clojure/clojure/core/cache.clj#L52 . Best regards, Andy -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
On 7 December 2014 at 05:13, Andy L wrote: > > > >> The SoftCache uses a ConcurrentHashMap, but that caching option isn't >> used in core.memoize. Are you building a custom memoizer? >> >> > WRT ConcurrentHashMap, it was an incorrect conclusion on my part. In any > case, I fail to see "thread safety" in the cache implementation, but again > I could be wrong. Or it might not be needed for 99.99% cache use cases. > Also, at that point I would like to avoid to "defcache" my own version. > Most of the cache implementations in core.cache have no side-effects. They simply return a new cache rather than overwriting the old one. The memoize library places the cache in an atom, so it's guaranteed to change atomically. > So I ended up with this (this is my first LISP macro ever, so please be > gentle :-) : > > (defmacro when-map-future-swap! [a k f] > `(locking ~a > (when (not (contains? @~a ~k)) >(swap! ~a assoc ~k nil) >(future (swap! ~a assoc ~k (~f ~k))) >) > ) > ) > You could write this as a function. There's nothing in there that requires a macro. (defn when-map-future-swap! [a k f] (locking a (when-not (contains? @a k) (swap! a assoc k nil) (future (swap! a assoc k (f k)) But I'd personally just use a delay rather than "locking" for this purpose. - James -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
or even better (using future themselves as a "marker" in the atom): (defmacro map-future-swap! [a k f] `(locking ~a (when (not (contains? @~a ~k)) (swap! ~a assoc ~k (future (swap! ~a assoc ~k (~f ~k ) ) ) -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
> The SoftCache uses a ConcurrentHashMap, but that caching option isn't used > in core.memoize. Are you building a custom memoizer? > > WRT ConcurrentHashMap, it was an incorrect conclusion on my part. In any case, I fail to see "thread safety" in the cache implementation, but again I could be wrong. Or it might not be needed for 99.99% cache use cases. Also, at that point I would like to avoid to "defcache" my own version. So I ended up with this (this is my first LISP macro ever, so please be gentle :-) : (defmacro when-map-future-swap! [a k f] `(locking ~a (when (not (contains? @~a ~k)) (swap! ~a assoc ~k nil) (future (swap! ~a assoc ~k (~f ~k))) ) ) ) Which seems to do what I need: user=> (defn f[k] (Thread/sleep 3000) k) #'user/f user=> (when-map-future-swap! a "arg" f) # user=> a # user=> (Thread/sleep 4000) nil user=> a # Andy -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
On 7 December 2014 at 01:13, Andy L wrote: > > Thanks for looking into that. This indeed would solve a "semantics" > problem of memoize, as it returns a value now. However, it seems that > clojure.core.memoize, > or rather clojure.core.cache memoize is based of, is not thread safe. > > It uses ConcurrentHashMap's "put" under the hood, instead of atomic > "putIfAbsent". I might be completely wrong here though. > The SoftCache uses a ConcurrentHashMap, but that caching option isn't used in core.memoize. Are you building a custom memoizer? - James -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
> (defn memoized [f] > (comp deref (memoize (fn [& args] (delay (apply f args) > > Thanks for looking into that. This indeed would solve a "semantics" problem of memoize, as it returns a value now. However, it seems that clojure.core.memoize, or rather clojure.core.cache memoize is based of, is not thread safe. It uses ConcurrentHashMap's "put" under the hood, instead of atomic "putIfAbsent". I might be completely wrong here though. Cheers, Andy -- 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/d/optout.
Re: atoms, memoize, future-s and CAS
It sounds like you want a delay. Delays are guaranteed to execute their body only once, so we can combine a delay with an atom: (defn memoized [f] (comp deref (memoize (fn [& args] (delay (apply f args) In theory that should produce a memoize that executes the function only once for each set of arguments. - James On 6 December 2014 at 21:32, Andy L wrote: > Hi, > > Here is the situation. There is a function "f" retrieving some data from > various sources (including reading files, a lot of io, e.g. map-reduce) > expected by design to return the same result for given input. Results of > "f" invocation from parallely running futures are stored in an atom wrapped > map and everything works just fine. > > With a small exception when "f" invocations with the same arguments > overlap - the same expensive "io" is kicked off 2 or more time s. Not a > tragedy, but still very unpleasant and wasteful. The expectation would be > that a subsequent "f" call would just bail without doing anything while > initial invocation assoc new data into an atom, > > The first intuition was to use memoize, however I do not think its > semantics fit well into this case, since the result is a "side-effect" on > an atom as opposed to return value. > > The easiest solution, is to create another atom with a map of the > arguments into a "state". If some other "future" is already there working > hard on the problem, we simply bail. However, that leads to another problem. > > "compare-and-set!" just operates on atoms as wholes, which is fine for > unstructured data, but falls short for things somewhat more complex, > like here. > > While updating an atom in this context is trivial: > > user=> (def a (atom {})) > user=> (swap! a assoc ["arg1" "arg2"] :PENDING) > {["arg1" "arg2"] "resultA"} > > I would like to link the condition and future together somehow like that: > > user=> (when ((complement contains?) @a ["arg1" "arg3"]) (swap! a assoc > ["arg1" "arg3"] :PENDING )) > > That obviously will not work, unless I wrap it with "locking", which is > not necessarily a nice thing to do. I also tried to use refs here, however > they do not fit well here either and the solution is not as nice as it > could be. > > After that long introduction, I would like ask for some insight > Thanks in advance ... > > > Best, > Andy > > > > > > > > > > > > -- > 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/d/optout. > -- 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/d/optout.
atoms, memoize, future-s and CAS
Hi, Here is the situation. There is a function "f" retrieving some data from various sources (including reading files, a lot of io, e.g. map-reduce) expected by design to return the same result for given input. Results of "f" invocation from parallely running futures are stored in an atom wrapped map and everything works just fine. With a small exception when "f" invocations with the same arguments overlap - the same expensive "io" is kicked off 2 or more time s. Not a tragedy, but still very unpleasant and wasteful. The expectation would be that a subsequent "f" call would just bail without doing anything while initial invocation assoc new data into an atom, The first intuition was to use memoize, however I do not think its semantics fit well into this case, since the result is a "side-effect" on an atom as opposed to return value. The easiest solution, is to create another atom with a map of the arguments into a "state". If some other "future" is already there working hard on the problem, we simply bail. However, that leads to another problem. "compare-and-set!" just operates on atoms as wholes, which is fine for unstructured data, but falls short for things somewhat more complex, like here. While updating an atom in this context is trivial: user=> (def a (atom {})) user=> (swap! a assoc ["arg1" "arg2"] :PENDING) {["arg1" "arg2"] "resultA"} I would like to link the condition and future together somehow like that: user=> (when ((complement contains?) @a ["arg1" "arg3"]) (swap! a assoc ["arg1" "arg3"] :PENDING )) That obviously will not work, unless I wrap it with "locking", which is not necessarily a nice thing to do. I also tried to use refs here, however they do not fit well here either and the solution is not as nice as it could be. After that long introduction, I would like ask for some insight Thanks in advance ... Best, Andy -- 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/d/optout.
Re: Expanding The Use Of Transducers To Atoms?
IMHO, for what you describe, i.e. "I'd like to view an atom's changes in state as a lazy sequence." there is no need to change the IAtom or add-watch function. Watchers are called for their side-effects, so if you want to consume their output as a "lazy sequence", you have to do that transformation step in the watcher function that you attach to the atom/ref/agent. Having said that, as changes to an atom happen asynchronously, I don't think that exposing it as lazy-seq is very efficient way of consuming the values. However, with the advent of core.async, there is now a very elegant way of consuming them via a channel and that channel can have a transducer stack attached (clojure 1.7+), so something along the lines of (def atom-to-watch (atom 0)) (defn make-watcher [out-ch-with-transducer] (fn [x] (async/put! out-ch-with-transducer x (def ch (async/chan 100 your-transducer-stack)) (add-watch atom-to-watch (make-watcher ch)) ;; somewhere else in your code you can consume the values (go (loop [v (async/: > > I've been reading about transducers with interest. > > The official docs at http://clojure.org/transducers say "*Because > transducers are decoupled from input or output sources, they can be used in > many different processes - collections, streams, channels, observables, > etc.* " > > At this stage, there is direct support for collections and core.async. But, > given the comment above about "observables", this got me to wondering > about another scenario ... > > I'd like to view an atom's changes in state as a lazy sequence. The first > state of the atom is like the first item in the seq, the next time the atom > changes state, its new state is the second item in the seq is generated, > etc. An infinite seq of new states. (I want to do this in the context of > clojurescript and a GUI library called reagent. Think FRP). > > Now imagine that I could attach a transducer to this seq of state changes, > so that I end up with a modified seq of state changes. > > Now, I can figure out how to do this by gluing together an atom watcher > with a core.sync channel. All doable with a small bit of work, I guess. > > But I wondered. Given the claim above about transducers and how they can > be used in the case of observables, should this atom-as-seq-with-transducer > be easier? Should the IAtom interface or the add-watcher function be > changed to make this process easier? > > Just a thought. > > -- > Mike > > > -- > 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/d/optout. > -- László Török Checkout justonemorepoint.com - Know your true value -- 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/d/optout.
Expanding The Use Of Transducers To Atoms?
I've been reading about transducers with interest. The official docs at http://clojure.org/transducers say "*Because transducers are decoupled from input or output sources, they can be used in many different processes - collections, streams, channels, observables, etc.* " At this stage, there is direct support for collections and core.async. But, given the comment above about "observables", this got me to wondering about another scenario ... I'd like to view an atom's changes in state as a lazy sequence. The first state of the atom is like the first item in the seq, the next time the atom changes state, its new state is the second item in the seq is generated, etc. An infinite seq of new states. (I want to do this in the context of clojurescript and a GUI library called reagent. Think FRP). Now imagine that I could attach a transducer to this seq of state changes, so that I end up with a modified seq of state changes. Now, I can figure out how to do this by gluing together an atom watcher with a core.sync channel. All doable with a small bit of work, I guess. But I wondered. Given the claim above about transducers and how they can be used in the case of observables, should this atom-as-seq-with-transducer be easier? Should the IAtom interface or the add-watcher function be changed to make this process easier? Just a thought. -- Mike -- 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/d/optout.
Re: futures and atoms and bears, oh my!
On Tue, Jul 15, 2014 at 9:44 AM, Stefan Kamphausen wrote: > > Note, that it may be a reasonable fix to your situation to change bar > instead of foo. This is possible by evaluating the new definition of bar > /later/; bar could also be a dynamically bindable Var, so that when > compiling foo, we do not know how to call bar correctly. That's the way > the compiler works. A linter like eastwood[1] might report this, though. > I was going to say the same thing about dynamic vars. Here's an example: user=> (defn ^:dynamic foo [x] (inc x)) #'user/foo user=> (foo 1) 2 user=> (binding [foo (fn [x y] (+ x y))] (foo 1 2)) 3 -- 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/d/optout.
Re: futures and atoms and bears, oh my!
> > (defn foo > "I don't do a whole lot." > [a b] > ((let [y (bar(a b))] > (println a b "Hello, World!" > > Now, *there* are some very suspicious parens around... 1. You're trying to call a as a function 2. Yes, you're calling bar with too few parameters, but how many? One. 3. Finally, after fixing that, you'd try to call nil as a function. Can you see, why? The '(('. ... just to be nitpicking and slightly off-topic, I know. Sorry. Note, that it may be a reasonable fix to your situation to change bar instead of foo. This is possible by evaluating the new definition of bar /later/; bar could also be a dynamically bindable Var, so that when compiling foo, we do not know how to call bar correctly. That's the way the compiler works. A linter like eastwood[1] might report this, though. Kind regards, stefan [1] https://github.com/jonase/eastwood > -- 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/d/optout.
Re: futures and atoms and bears, oh my!
You're right and ouch! That's horrible. It's an error that should be known at eval time. On Tuesday, July 15, 2014 1:20:04 PM UTC+1, Jony Hudson wrote: > > I think that's what you'd expect. This will also evaluate just fine: > > (defn foo > [x y] > (bar x y)) > > but will fail at run-time too. > > > Jony > > On Tuesday, 15 July 2014 13:07:43 UTC+1, edw...@kenworthy.info wrote: >> >> Creating a new project in Lein then opening it in Light Table and with >> minimal edits: >> >> (ns test.core) >> >> (defn bar [a b c]) >> >> (defn foo >> "I don't do a whole lot." >> [a b] >> ((let [y (bar(a b))] >> (println a b "Hello, World!" >> >> foo evaluates without error despite calling bar with too few parameters. >> >> -- 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/d/optout.
Re: futures and atoms and bears, oh my!
I think that's what you'd expect. This will also evaluate just fine: (defn foo [x y] (bar x y)) but will fail at run-time too. Jony On Tuesday, 15 July 2014 13:07:43 UTC+1, edw...@kenworthy.info wrote: > > Creating a new project in Lein then opening it in Light Table and with > minimal edits: > > (ns test.core) > > (defn bar [a b c]) > > (defn foo > "I don't do a whole lot." > [a b] > ((let [y (bar(a b))] > (println a b "Hello, World!" > > foo evaluates without error despite calling bar with too few parameters. > > -- 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/d/optout.
Re: futures and atoms and bears, oh my!
On Tuesday, July 15, 2014 12:38:53 PM UTC+1, Jeremy Heiler wrote: > > On Tue, Jul 15, 2014 at 3:15 AM, > > wrote: > >> Curiouser and curiouser. >> >> I turns out the problem was *not* with my next-to-play function but >> rather with the fact that it takes three arguments but I was only passing >> it two. >> >> The curious part is that whilst the compiler complained about the wrong >> arity if I evaluated the call directly, it didn't when it was part of a let! >> > > Are you able to reproduce this problem with a fresh environment? > > Yes. Creating a new project in Lein then opening it in Light Table and with minimal edits: (ns test.core) (defn bar [a b c]) (defn foo "I don't do a whole lot." [a b] ((let [y (bar(a b))] (println a b "Hello, World!" foo evaluates without error despite calling bar with too few parameters. I suspect in my code next-to-play is messing up the stack because it pulls 3 parameters off the stack when only 2 have been placed on it. >> (let [next-player (next-to-play @current-board player)]... >> >> should be: >> >> (let [next-player (next-to-play @current-board player false)]... >> >> But the compiler doesn't complain! >> > -- 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/d/optout.
Re: futures and atoms and bears, oh my!
On Tue, Jul 15, 2014 at 3:15 AM, wrote: > Curiouser and curiouser. > > I turns out the problem was *not* with my next-to-play function but rather > with the fact that it takes three arguments but I was only passing it two. > > The curious part is that whilst the compiler complained about the wrong > arity if I evaluated the call directly, it didn't when it was part of a let! > Are you able to reproduce this problem with a fresh environment? > > (let [next-player (next-to-play @current-board player)]... > > should be: > > (let [next-player (next-to-play @current-board player false)]... > > But the compiler doesn't complain! > -- 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/d/optout.
Re: futures and atoms and bears, oh my!
Curiouser and curiouser. I turns out the problem was *not* with my next-to-play function but rather with the fact that it takes three arguments but I was only passing it two. The curious part is that whilst the compiler complained about the wrong arity if I evaluated the call directly, it didn't when it was part of a let! (let [next-player (next-to-play @current-board player)]... should be: (let [next-player (next-to-play @current-board player false)]... But the compiler doesn't complain! On Tuesday, July 15, 2014 7:06:36 AM UTC+1, edw...@kenworthy.info wrote: > > Quick follow up, replacing get-and-make-move with > > (defn get-and-make-move > [board strategy player] > board) > > Still have the same problem: so the issue is not with that function nor > any of the functions it calls (nor the strategies). > > Beginning to think it's my next-to-play function, which would be weird as, > again, it works in the single threaded command line version. > > > > > On Tuesday, July 15, 2014 6:41:05 AM UTC+1, edw...@kenworthy.info wrote: >> >> Pretty sure the strategy isn't a problem (random-strategy picks a random >> move from all legal moves) and it works in the single-threaded command line >> version of the app. >> >> ditto all-directions which is constant: >> >> (def ^:constant all-directions >> "Defines the array of all possible directions from a square." >> [[-1 -1][0 -1][+1 -1] >>[-1 0] [+1 0] >>[-1 +1][0 +1][+1 +1]]) >> >> Reasonable suggestions though. >> >> I think I'll have to create a version of get-and-make-move that just >> returns a random board (i.e. is as simple as possible) and see what happens. >> >> Is there a way to trace into a thread created by (future) ? >> >> On Tuesday, July 15, 2014 12:57:33 AM UTC+1, Gary Johnson wrote: >>> >>> Looking at this code without further knowledge of the strategy function, >>> my first guess is simply that your strategy function may not be returning a >>> result which satisfies the valid-move? and legal-move? predicates thus >>> throwing you into an infinite loop. Possibly the printf is being suppressed >>> within the swap! operation, but some testing would be required to see if >>> this is the case generally. The other obvious potential for a hiccup would >>> be if all-directions is somehow growing with each iteration of make-move, >>> thus preventing idx from ever exceeding its length. Not knowing what is >>> going on inside all these functions makes this a rather tricky bit of guess >>> work at best. Anyway, I'd try running get-move from the repl to see how >>> likely it is to get stuck in an infinite loop. >>> >>> Good luck, >>> ~Gary >>> >> -- 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/d/optout.
Re: futures and atoms and bears, oh my!
Quick follow up, replacing get-and-make-move with (defn get-and-make-move [board strategy player] board) Still have the same problem: so the issue is not with that function nor any of the functions it calls (nor the strategies). Beginning to think it's my next-to-play function, which would be weird as, again, it works in the single threaded command line version. On Tuesday, July 15, 2014 6:41:05 AM UTC+1, edw...@kenworthy.info wrote: > > Pretty sure the strategy isn't a problem (random-strategy picks a random > move from all legal moves) and it works in the single-threaded command line > version of the app. > > ditto all-directions which is constant: > > (def ^:constant all-directions > "Defines the array of all possible directions from a square." > [[-1 -1][0 -1][+1 -1] >[-1 0] [+1 0] >[-1 +1][0 +1][+1 +1]]) > > Reasonable suggestions though. > > I think I'll have to create a version of get-and-make-move that just > returns a random board (i.e. is as simple as possible) and see what happens. > > Is there a way to trace into a thread created by (future) ? > > On Tuesday, July 15, 2014 12:57:33 AM UTC+1, Gary Johnson wrote: >> >> Looking at this code without further knowledge of the strategy function, >> my first guess is simply that your strategy function may not be returning a >> result which satisfies the valid-move? and legal-move? predicates thus >> throwing you into an infinite loop. Possibly the printf is being suppressed >> within the swap! operation, but some testing would be required to see if >> this is the case generally. The other obvious potential for a hiccup would >> be if all-directions is somehow growing with each iteration of make-move, >> thus preventing idx from ever exceeding its length. Not knowing what is >> going on inside all these functions makes this a rather tricky bit of guess >> work at best. Anyway, I'd try running get-move from the repl to see how >> likely it is to get stuck in an infinite loop. >> >> Good luck, >> ~Gary >> > -- 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/d/optout.
Re: futures and atoms and bears, oh my!
Pretty sure the strategy isn't a problem (random-strategy picks a random move from all legal moves) and it works in the single-threaded command line version of the app. ditto all-directions which is constant: (def ^:constant all-directions "Defines the array of all possible directions from a square." [[-1 -1][0 -1][+1 -1] [-1 0] [+1 0] [-1 +1][0 +1][+1 +1]]) Reasonable suggestions though. I think I'll have to create a version of get-and-make-move that just returns a random board (i.e. is as simple as possible) and see what happens. Is there a way to trace into a thread created by (future) ? On Tuesday, July 15, 2014 12:57:33 AM UTC+1, Gary Johnson wrote: > > Looking at this code without further knowledge of the strategy function, > my first guess is simply that your strategy function may not be returning a > result which satisfies the valid-move? and legal-move? predicates thus > throwing you into an infinite loop. Possibly the printf is being suppressed > within the swap! operation, but some testing would be required to see if > this is the case generally. The other obvious potential for a hiccup would > be if all-directions is somehow growing with each iteration of make-move, > thus preventing idx from ever exceeding its length. Not knowing what is > going on inside all these functions makes this a rather tricky bit of guess > work at best. Anyway, I'd try running get-move from the repl to see how > likely it is to get stuck in an infinite loop. > > Good luck, > ~Gary > -- 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/d/optout.
Re: futures and atoms and bears, oh my!
Looking at this code without further knowledge of the strategy function, my first guess is simply that your strategy function may not be returning a result which satisfies the valid-move? and legal-move? predicates thus throwing you into an infinite loop. Possibly the printf is being suppressed within the swap! operation, but some testing would be required to see if this is the case generally. The other obvious potential for a hiccup would be if all-directions is somehow growing with each iteration of make-move, thus preventing idx from ever exceeding its length. Not knowing what is going on inside all these functions makes this a rather tricky bit of guess work at best. Anyway, I'd try running get-move from the repl to see how likely it is to get stuck in an infinite loop. Good luck, ~Gary -- 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/d/optout.
Re: futures and atoms and bears, oh my!
(defn get-move "Call the player's strategy function to get a move. Keep calling until a valid and legal move is returned and pass that back. There is no way to escape without the strategy returning a valid and legal move." [board strategy player] (let [[x y :as move] (strategy board player)] (if (and (valid-move? board move) (legal-move? board player move)) move ; return the move (do (printf "!Attempted illegal move [%d %d] by %s.\n" x y player) (recur board strategy player) (defn make-move "Update board to reflect move by a player" [board move player] ;; First make the move, then make any flips (loop [brd (place-piece board move player) idx 0] (if (>= idx (count all-directions)) brd (recur (make-flips brd move player (all-directions idx)) (inc idx) (defn- get-and-make-move "Gets a valid and legal move from the strategy and then makes it, returning the new board. This does what the PAIP 'get-move' function did." [board strategy player] (let [[x y :as move] (get-move board strategy player)] (make-move board move player))) On Monday, July 14, 2014 12:35:47 PM UTC+1, James Reeves wrote: > > Could you post more of your code? If you suspect your code is stopping at > the first swap!, it might be an idea to post the contents of > get-and-make-move > as well. > > - James > > > On 14 July 2014 11:25, > wrote: > >> So I've got something strange happening. >> >> I have a function (play, see below) which I spin off in a separate thread: >> >> (future (play {:black black-strategy :white white-strategy} :black)) >> >> The weird thing is whilst the first (println) in play is printed to the >> console, and so is a similar print from the watch I have on current-board, >> the play thread seems to stall at that point: I never see "done swap" or >> any other prints from play and my UI doesn't update past the initial change >> to current-board. >> >> It's almost as if swap! does it's job but then never returns. >> >> Any pointers for me? >> >> >> (defn play [player-strategies player] >> (println "play called (next is waiting 5 seconds before doing >> anything.") >> (Thread/sleep 5000) >> (swap! current-board #(get-and-make-move %1 (player-strategies player) >> player)) >> (println "done swap!") >> (let [next-player (next-to-play @current-board player)] >> (if-not next-player >> (let [result (count-difference :black)] >> (printf "GAME OVER");; should >> return the result >> (print-board @current-board) >> ; (print (result-string result)) >> (newline) ;) >> result) >> (recur player-strategies next-player) >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com . >> 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 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/d/optout.
Re: futures and atoms and bears, oh my!
Could you post more of your code? If you suspect your code is stopping at the first swap!, it might be an idea to post the contents of get-and-make-move as well. - James On 14 July 2014 11:25, wrote: > So I've got something strange happening. > > I have a function (play, see below) which I spin off in a separate thread: > > (future (play {:black black-strategy :white white-strategy} :black)) > > The weird thing is whilst the first (println) in play is printed to the > console, and so is a similar print from the watch I have on current-board, > the play thread seems to stall at that point: I never see "done swap" or > any other prints from play and my UI doesn't update past the initial change > to current-board. > > It's almost as if swap! does it's job but then never returns. > > Any pointers for me? > > > (defn play [player-strategies player] > (println "play called (next is waiting 5 seconds before doing anything.") > (Thread/sleep 5000) > (swap! current-board #(get-and-make-move %1 (player-strategies player) > player)) > (println "done swap!") > (let [next-player (next-to-play @current-board player)] > (if-not next-player > (let [result (count-difference :black)] > (printf "GAME OVER");; should > return the result > (print-board @current-board) > ; (print (result-string result)) > (newline) ;) > result) > (recur player-strategies next-player) > > -- > 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/d/optout. > -- 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/d/optout.
futures and atoms and bears, oh my!
So I've got something strange happening. I have a function (play, see below) which I spin off in a separate thread: (future (play {:black black-strategy :white white-strategy} :black)) The weird thing is whilst the first (println) in play is printed to the console, and so is a similar print from the watch I have on current-board, the play thread seems to stall at that point: I never see "done swap" or any other prints from play and my UI doesn't update past the initial change to current-board. It's almost as if swap! does it's job but then never returns. Any pointers for me? (defn play [player-strategies player] (println "play called (next is waiting 5 seconds before doing anything.") (Thread/sleep 5000) (swap! current-board #(get-and-make-move %1 (player-strategies player) player)) (println "done swap!") (let [next-player (next-to-play @current-board player)] (if-not next-player (let [result (count-difference :black)] (printf "GAME OVER");; should return the result (print-board @current-board) ; (print (result-string result)) (newline) ;) result) (recur player-strategies next-player) -- 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/d/optout.
Re: using atoms as logs for channels in core.async
The function map> takes a channel and a function, and returns a new channel; every time an element is sent through that new channel, it first goes through the given function (and it is the result of that function that is actually sent through the original channel). The function map< is similar, except it applies the given function to each element that exits the channel. So in my function, (as/map< (fn [x] (swap! at pop) x) chan) creates a new channel that will remove an element from the sequence referenced by the atom at every time a value is sent through it. The result of the function is thus a new channel that conjes all of its input to the atom, and pops an element from the atom every time someone takes from it. But from an external point of view, thanks to both functions returning the element unchanged, it acts exactly like a normal channel. Note that it essentially wraps the original channel within two other channels, so the original channel is unchanged and should therefore not be used anymore. I have to leave now; if you still have any question after playing with the following code, I'll be glad to answer them when I come back (in ~10 hours or so) ;; project.clj (defproject async "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME"; :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/core.async "0.1.303.0-886421-alpha"]] :main ^:skip-aot async.core :target-path "target/%s" :profiles {:uberjar {:aot :all}}) ;; src/async/core.clj (ns async.core (:require [clojure.core.async :as as :refer [go ! chan]])) (defn decorate-channel [chan at] (as/map> (fn [x] (swap! at conj x) x) (as/map< (fn [x] (swap! at pop) x) chan))) (defn some-fn-using-a-channel [ch] (go (dotimes [_ 10] (! ch 1))) (go (dotimes [_ 10] ( wrote: > Hi Gary, > > Your function looks interesting and succinct, but I am still new to this > subject so am not sure how it would be used. Could you give some examples? > > Jesse > > > On Wednesday, May 14, 2014 3:34:17 AM UTC+9, Gary Verhaegen wrote: >> >> What about the following? (as is bound to clojure.core.async ns) >> >> (defn decorate-channel >> [chan at] >> (as/map> (fn [x] (swap! at conj x) x) >>(as/map< (fn [x] (swap! at pop) x) >>chan))) >> >> As far as I can tell, it should do what you want, without introducing >> global vars. It also returns a "normal" async channel that can be used >> anywhere a channel is expected, without special handling. This could >> be very handy for debugging. >> >> >> On 13 May 2014 06:02, gamma235 wrote: >> > >> > Hey guys, I took your suggestions and just wanna deliver the finished >> > product. I included the macro in there for practice, but agree it is >> > probably not necessary. Thanks for all your help. >> > >> > p is for pretty :) >> > >> >> >> >> (defn pchan [ch] >> >> >> >> {:channel ch, :buffer (atom [])}) >> > >> > >> >> >> >> (defn pbuff [{:keys [ch buffer]}] >> >>(println @buffer)) >> > >> > >> >> >> >> (defn pput [{:keys [channel buffer]} v] >> >> (do >> >> (go >> >> (>! channel v)) >> >> (swap! buffer conj v) >> >> (println "put " v))) >> > >> > >> >> >> >> (defn ptake [{:keys [channel buffer]}] >> >> (go >> >> (let [v (> >>(if-not (empty? @buffer) >> >> (do >> >>(swap! buffer pop) >> >>(println "took " v) >> >> (println "take pending ...")) >> > >> > >> >> >> >> (defmacro def-pchan >> >> ([name] >> >>`(def ~name (pchan (chan >> >> ([name buff] >> >>`(def ~name (pchan (chan ~buff) >> > >> > >> >> >> >> (defn clear-buffer [{:keys [buffer]}] >> >> (reset! buffer [])) >> >> >> > it works! >> >> >> >> (def-pchan pc) >> >> (:buffer pc) >> >> (pbuff pc) >> >> (ptake pc) >> >> (pput pc 42) >> >> (clear-buffer pc) >> > >> > -- >> > You received this message because you are subscribed to the Google >> > Groups "Clojure" group. >> > To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com. >> > 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 clojure@googlegroups.com > Note that posts from new members are moderated - please be patien
Re: using atoms as logs for channels in core.async
Hi Gary, Your function looks interesting and succinct, but I am still new to this subject so am not sure how it would be used. Could you give some examples? Jesse On Wednesday, May 14, 2014 3:34:17 AM UTC+9, Gary Verhaegen wrote: > > What about the following? (as is bound to clojure.core.async ns) > > (defn decorate-channel > [chan at] > (as/map> (fn [x] (swap! at conj x) x) >(as/map< (fn [x] (swap! at pop) x) >chan))) > > As far as I can tell, it should do what you want, without introducing > global vars. It also returns a "normal" async channel that can be used > anywhere a channel is expected, without special handling. This could > be very handy for debugging. > > > On 13 May 2014 06:02, gamma235 > > wrote: > > > > Hey guys, I took your suggestions and just wanna deliver the finished > > product. I included the macro in there for practice, but agree it is > > probably not necessary. Thanks for all your help. > > > > p is for pretty :) > > > >> > >> (defn pchan [ch] > >> > >> {:channel ch, :buffer (atom [])}) > > > > > >> > >> (defn pbuff [{:keys [ch buffer]}] > >>(println @buffer)) > > > > > >> > >> (defn pput [{:keys [channel buffer]} v] > >> (do > >> (go > >> (>! channel v)) > >> (swap! buffer conj v) > >> (println "put " v))) > > > > > >> > >> (defn ptake [{:keys [channel buffer]}] > >> (go > >> (let [v ( >>(if-not (empty? @buffer) > >> (do > >>(swap! buffer pop) > >>(println "took " v) > >> (println "take pending ...")) > > > > > >> > >> (defmacro def-pchan > >> ([name] > >>`(def ~name (pchan (chan > >> ([name buff] > >>`(def ~name (pchan (chan ~buff) > > > > > >> > >> (defn clear-buffer [{:keys [buffer]}] > >> (reset! buffer [])) > >> > > it works! > >> > >> (def-pchan pc) > >> (:buffer pc) > >> (pbuff pc) > >> (ptake pc) > >> (pput pc 42) > >> (clear-buffer pc) > > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com . > > 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 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/d/optout.
Re: using atoms as logs for channels in core.async
What about the following? (as is bound to clojure.core.async ns) (defn decorate-channel [chan at] (as/map> (fn [x] (swap! at conj x) x) (as/map< (fn [x] (swap! at pop) x) chan))) As far as I can tell, it should do what you want, without introducing global vars. It also returns a "normal" async channel that can be used anywhere a channel is expected, without special handling. This could be very handy for debugging. On 13 May 2014 06:02, gamma235 wrote: > > Hey guys, I took your suggestions and just wanna deliver the finished > product. I included the macro in there for practice, but agree it is > probably not necessary. Thanks for all your help. > > p is for pretty :) > >> >> (defn pchan [ch] >> >> {:channel ch, :buffer (atom [])}) > > >> >> (defn pbuff [{:keys [ch buffer]}] >>(println @buffer)) > > >> >> (defn pput [{:keys [channel buffer]} v] >> (do >> (go >> (>! channel v)) >> (swap! buffer conj v) >> (println "put " v))) > > >> >> (defn ptake [{:keys [channel buffer]}] >> (go >> (let [v (>(if-not (empty? @buffer) >> (do >>(swap! buffer pop) >>(println "took " v) >> (println "take pending ...")) > > >> >> (defmacro def-pchan >> ([name] >>`(def ~name (pchan (chan >> ([name buff] >>`(def ~name (pchan (chan ~buff) > > >> >> (defn clear-buffer [{:keys [buffer]}] >> (reset! buffer [])) >> > it works! >> >> (def-pchan pc) >> (:buffer pc) >> (pbuff pc) >> (ptake pc) >> (pput pc 42) >> (clear-buffer pc) > > -- > 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/d/optout. -- 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/d/optout.
Re: using atoms as logs for channels in core.async
Hey guys, I took your suggestions and just wanna deliver the finished product. I included the macro in there for practice, but agree it is probably not necessary. Thanks for all your help. p is for pretty :) > (defn pchan [ch] > {:channel ch, :buffer (atom [])}) > > (defn pbuff [{:keys [ch buffer]}] >(println @buffer)) > > (defn pput [{:keys [channel buffer]} v] > (do > (go > (>! channel v)) > (swap! buffer conj v) > (println "put " v))) > > (defn ptake [{:keys [channel buffer]}] > (go > (let [v ((if-not (empty? @buffer) > (do >(swap! buffer pop) >(println "took " v) > (println "take pending ...")) > > (defmacro def-pchan > ([name] >`(def ~name (pchan (chan > ([name buff] >`(def ~name (pchan (chan ~buff) > > (defn clear-buffer [{:keys [buffer]}] > (reset! buffer [])) > > it works! > (def-pchan pc) > (:buffer pc) > (pbuff pc) > (ptake pc) > (pput pc 42) > (clear-buffer pc) -- 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/d/optout.
Re: using atoms as logs for channels in core.async
Ok the destructuring is clear to me now. And yes Jay Field article was great :) So the only thing that remains now is to get the symbol being passed into my original transparent-put function to stop evaluating to either ch-log or clojure.core.async.impl.channels.ManyToManyChannel@5096B86b-log I'm using your macro David but it still won't put with an update to the atom. Jesse -- 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/d/optout.
Re: using atoms as logs for channels in core.async
On 12 May 2014 10:48, gamma235 wrote: > When I try this using your code above I get a stack-trace that I can't > understand. Am I using it wrong? > > (transparent-chan c) >> (transparent-put c 42) >> (transparent-take c) >> > Yep, try this instead: (def tc (transparent-chan c)) (transparent-put tc 42) (transparent-take tc) I'm creating a new data structure that contains both a channel and an atom, and I'm returning it from transparent-ch. I'm not modifying the original channel in any fashion. The destructuring is just a shortcut. This code: (defn transparent-put [{:keys [channel buffer]} x] (go (>! channel x) (swap! buffer conj x))) Is equivalent to: (defn transparent-put [tc x] (let [{:keys [channel buffer]} tc] (go (>! channel x) (swap! buffer conj x))) Which is equivalent to: (defn transparent-put [tc x] (let [channel (:channel tc) buffer (:buffer tc)] (go (>! channel x) (swap! buffer conj x))) - James -- 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/d/optout.
Re: using atoms as logs for channels in core.async
>> >> >> 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/> "got >> >> msg " >> >> msg " from channel " 'c))) >> >> >> >> ...try this instead: >> >> >> >> (def my-go-loop (async/go-loop [] (let [msg (async/> (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/> (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 >> >>
Re: using atoms as logs for channels in core.async
> 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/ (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
Re: using atoms as logs for channels in core.async
m 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/ >> msg " > >> msg " from channel " 'c))) > >> > >> ...try this instead: > >> > >> (def my-go-loop (async/go-loop [] (let [msg (async/ "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 :
Re: using atoms as logs for channels in core.async
now 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/> msg " >> msg " from channel " 'c))) >> >> ...try this instead: >> >> (def my-go-loop (async/go-loop [] (let [msg (async/> 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/> 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 [])) >
Re: using atoms as logs for channels in core.async
> > 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/ 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 ( >> log-name (symbol (str ch '-log))] > >> (swap! log-name #(remove #{v} %)) > >>(println v "has been removed from channel"))) > >> (println " removal pending")) > >> > >> > >> &
Re: using atoms as logs for channels in core.async
When I try this using your code above I get a stack-trace that I can't understand. Am I using it wrong? (transparent-chan c) > (transparent-put c 42) > (transparent-take c) - > >"Exception in thread \"async-dispatch-64\" " >"java.lang.IllegalArgumentException: No implementation of method: >:take! of protocol: #'clojure.core.async.impl.protocols/ReadPort found for >class: nil" >"\tat clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:541)" On Monday, May 12, 2014 1:16:19 PM UTC+9, James Reeves wrote: > > On 12 May 2014 03:41, gamma235 > wrote: > >> >> (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!"))) >>> >> > This looks like you're replicating the functionality of maps using defs. > Instead, consider something like: > > (defn transparent-chan [ch] > {:channel ch, :buffer (atom [])}) > > Another improvement you may wish to consider is to use a queue, rather > than a vector. Immutable queues exist in Clojure, but are something of a > hidden feature. > > (defn transparent-chan [ch] > {:channel ch, :buffer (atom clojure.lang.PersistentQueue/EMPTY)}) > > Queues act more like channels, in that popping a queue strips off the > oldest item, whereas popping a vector strips off the newest. > > With this in mind, you could write functions like: > > (defn transparent-put [{:keys [channel buffer]} x] > (go > (>! channel x) > (swap! buffer conj x))) > > (defn transparent-take [{:keys [channel buffer]} x] > (go > (let [x ( (swap! buffer pop) > x))) > > (defn transparent-buffer [{keys [buffer]}] > (vec @buffer)) > > - James > -- 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/d/optout.
Re: using atoms as logs for channels in core.async
Thanks James, I played around with the persistent queues before I started this exercise, but opted for atoms, after seeing this behavior (a la JOC): <https://lh6.googleusercontent.com/-4u0XBfNvbv4/U3CMpigLRoI/BjE/HDjKbcvSgAM/s1600/Screen+Shot+2014-05-12+at+5.55.27+PM.png> I never considered sticking the persistent queue in the atom and your code above made me realize that maps are a way better way to do this. Rock on, Jesse On Monday, May 12, 2014 1:16:19 PM UTC+9, James Reeves wrote: > > On 12 May 2014 03:41, gamma235 > wrote: > >> >> (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!"))) >>> >> > This looks like you're replicating the functionality of maps using defs. > Instead, consider something like: > > (defn transparent-chan [ch] > {:channel ch, :buffer (atom [])}) > > Another improvement you may wish to consider is to use a queue, rather > than a vector. Immutable queues exist in Clojure, but are something of a > hidden feature. > > (defn transparent-chan [ch] > {:channel ch, :buffer (atom clojure.lang.PersistentQueue/EMPTY)}) > > Queues act more like channels, in that popping a queue strips off the > oldest item, whereas popping a vector strips off the newest. > > With this in mind, you could write functions like: > > (defn transparent-put [{:keys [channel buffer]} x] > (go > (>! channel x) > (swap! buffer conj x))) > > (defn transparent-take [{:keys [channel buffer]} x] > (go > (let [x ( (swap! buffer pop) > x))) > > (defn transparent-buffer [{keys [buffer]}] > (vec @buffer)) > > - James > -- 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/d/optout.
Re: using atoms as logs for channels in core.async
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/ msg " from channel " 'c))) > > ...try this instead: > > (def my-go-loop (async/go-loop [] (let [msg (async/ 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/ > 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-
Re: using atoms as logs for channels in core.async
I apologize, apparently you can't use go-loop how I did below, => (def my-go-loop (async/go-loop [msg (async/ >> 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/ 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 (> 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 upd
Re: using atoms as logs for channels in core.async
> 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/ (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 ( 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 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 mo
Re: using atoms as logs for channels in core.async
On 12 May 2014 03:41, gamma235 wrote: > > (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!"))) >> > This looks like you're replicating the functionality of maps using defs. Instead, consider something like: (defn transparent-chan [ch] {:channel ch, :buffer (atom [])}) Another improvement you may wish to consider is to use a queue, rather than a vector. Immutable queues exist in Clojure, but are something of a hidden feature. (defn transparent-chan [ch] {:channel ch, :buffer (atom clojure.lang.PersistentQueue/EMPTY)}) Queues act more like channels, in that popping a queue strips off the oldest item, whereas popping a vector strips off the newest. With this in mind, you could write functions like: (defn transparent-put [{:keys [channel buffer]} x] (go (>! channel x) (swap! buffer conj x))) (defn transparent-take [{:keys [channel buffer]} x] (go (let [x (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/d/optout.
using atoms as logs for channels in core.async
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 ( 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 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/d/optout.
Re: Reactive Patterns with Atoms - am I using too much state?
Okay, got it. It looks like you're using agents where I'd been using atoms. Not sure if there's much of a difference for these use cases... the one-directional flow of source -> state -> watcher update notification -> ui change seems to work well with both agents and atoms. Brian Marick wrote: On Nov 30, 2013, at 10:39 AM, Sam Ritchie wrote: Brian, I like that too. It looks like you're providing the state when you do the def-action? If I understand the question right, yes. A test of a state function would look like: (fact (incrementer {:value 1} 3) => {:value 4})) Is the "self" variable "state", captured through the closure? `self` is the agent, whose dereference is passed in as the symbol named `state`. That part I'm uncomfortable with. I've put each agent in a namespace with its action functions. The convention is that the agent is named `self`, and `def-action` knows that convention. It works, but it reminds me too much of singletons and all those cases where you start out thinking a single instance is all you'll ever need and then discover you were wrong. Latest book: /Functional Programming for the Object-Oriented Programmer/ https://leanpub.com/fp-oo -- Sam Ritchie (@sritchie) Paddleguru Co-Founder 703.863.8561 www.paddleguru.com <http://www.paddleguru.com/> Twitter <http://twitter.com/paddleguru>// Facebook <http://facebook.com/paddleguru> -- -- 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.
Re: Reactive Patterns with Atoms - am I using too much state?
On Nov 30, 2013, at 10:39 AM, Sam Ritchie wrote: > Brian, I like that too. It looks like you're providing the state when you do > the def-action? If I understand the question right, yes. A test of a state function would look like: (fact (incrementer {:value 1} 3) => {:value 4})) > Is the "self" variable "state", captured through the closure? `self` is the agent, whose dereference is passed in as the symbol named `state`. That part I'm uncomfortable with. I've put each agent in a namespace with its action functions. The convention is that the agent is named `self`, and `def-action` knows that convention. It works, but it reminds me too much of singletons and all those cases where you start out thinking a single instance is all you'll ever need and then discover you were wrong. Latest book: /Functional Programming for the Object-Oriented Programmer/ https://leanpub.com/fp-oo -- -- 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.
Re: Reactive Patterns with Atoms - am I using too much state?
Interesting; I had started playing with the core.async approach, and it's good to see that Pedestal's on that same path. Brian, I like that too. It looks like you're providing the state when you do the def-action? Is the "self" variable "state", captured through the closure? Walter van der Laan wrote: An alternative that I'm looking at is pedestal 0.3.0. It sort of works like this... ;; Create a transform-channel and transform-function to handle all changes to 'state' (defn init [] (let [c (chan)] (go (while true (when-let [[path v] (! transform-chan [path v])) ;; Change the state by calling transform (transform [athlete-number :active?] true) (transform [athlete-number :timestamp] ms) ;; Create an inform-channel where functions can subscribe to changes in 'state' (def inform-channel-subscriptions [[update-timestamp [:* :timestamp]] [update-active [:* :active?]]]) This approach is described in: https://github.com/pedestal/pedestal/blob/master/app/examples/walkthrough.clj On Friday, November 29, 2013 6:58:32 PM UTC+1, Sam Ritchie wrote: Hey guys, As I start to work on more Clojurescript UI code, I've been running into a pattern with atoms and watches that I THINK I can abstract away... but the solution feels wrong, and I'd love to hear a better way. Say I'm building a stopwatch for timing runners in a race. I've got a clojure record like this: (defrecord StopwatchState [ active? ;; timer running? timestamp ;; UTC time of this particular state stopwatch-time ;; the time on the stopwatch as of "timestamp" results ;; pairs of [athlete number, time]]) and a bunch of functions that toggle the timer, mark an athlete crossing the line, update the timer, etc. My view holds the current state in an atom: (def state (atom ,,some-stopwatch-state)) and I update my views by adding watches to the atom and refreshing the various UI components to match the new state. Now! Here's the annoying pattern. In the cljs UI world, to poke these atoms, I end up wrapping all of my model functions like this: (defn toggle! [] (swap! state toggle)) (defn mark! [athlete-number] (swap! state mark athlete-number)) I can think of two ways to break the pattern. 1) A deep-code-walking macro that transforms code like (mark state athlete-number) into (swap! state mark athlete-number) if the first argument is an atom; 2) a defstatefn macro that defines the "mark" and "mark!" versions at the same time. Both feel wrong. My goal is to program in a more declarative way. Is there a better way to structure UI code? -- Sam Ritchie (@sritchie) Paddleguru Co-Founder 703.863.8561 www.paddleguru.com <http://www.paddleguru.com/> Twitter <http://twitter.com/paddleguru>// Facebook <http://facebook.com/paddleguru> -- -- 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. -- Sam Ritchie (@sritchie) Paddleguru Co-Founder 703.863.8561 www.paddleguru.com <http://www.paddleguru.com/> Twitter <http://twitter.com/paddleguru>// Facebook <http://facebook.com/paddleguru> -- -- 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.
Re: Reactive Patterns with Atoms - am I using too much state?
An alternative that I'm looking at is pedestal 0.3.0. It sort of works like this... ;; Create a transform-channel and transform-function to handle all changes to 'state' (defn init [] (let [c (chan)] (go (while true (when-let [[path v] (! transform-chan [path v])) ;; Change the state by calling transform (transform [athlete-number :active?] true) (transform [athlete-number :timestamp] ms) ;; Create an inform-channel where functions can subscribe to changes in 'state' (def inform-channel-subscriptions [[update-timestamp [:* :timestamp]] [update-active [:* :active?]]]) This approach is described in: https://github.com/pedestal/pedestal/blob/master/app/examples/walkthrough.clj On Friday, November 29, 2013 6:58:32 PM UTC+1, Sam Ritchie wrote: > > Hey guys, > > As I start to work on more Clojurescript UI code, I've been running into a > pattern with atoms and watches that I THINK I can abstract away... but the > solution feels wrong, and I'd love to hear a better way. > > Say I'm building a stopwatch for timing runners in a race. I've got a > clojure record like this: > > (defrecord StopwatchState [ > active? ;; timer running? > timestamp ;; UTC time of this particular state > stopwatch-time ;; the time on the stopwatch as of "timestamp" > results ;; pairs of [athlete number, time]]) > > and a bunch of functions that toggle the timer, mark an athlete crossing > the line, update the timer, etc. > > My view holds the current state in an atom: > > (def state (atom ,,some-stopwatch-state)) > > and I update my views by adding watches to the atom and refreshing the > various UI components to match the new state. > > Now! Here's the annoying pattern. In the cljs UI world, to poke these > atoms, I end up wrapping all of my model functions like this: > > (defn toggle! [] > (swap! state toggle)) > (defn mark! [athlete-number] > (swap! state mark athlete-number)) > > I can think of two ways to break the pattern. > > 1) A deep-code-walking macro that transforms code like (mark state > athlete-number) into (swap! state mark athlete-number) if the first > argument is an atom; > 2) a defstatefn macro that defines the "mark" and "mark!" versions at the > same time. > > Both feel wrong. My goal is to program in a more declarative way. Is there > a better way to structure UI code? > > -- > Sam Ritchie (@sritchie) > Paddleguru Co-Founder > 703.863.8561 > www.paddleguru.com > Twitter <http://twitter.com/paddleguru> // > Facebook<http://facebook.com/paddleguru> > -- -- 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.
Re: Reactive Patterns with Atoms - am I using too much state?
On Nov 29, 2013, at 11:58 AM, Sam Ritchie wrote: > 2) a defstatefn macro that defines the "mark" and "mark!" versions at the > same time. I do that with agents: (def-action text :send [state number message]) … creates a `text*` and a `text>!`, where `test>!` is (defn text>! [number message] (send self text* number message)) A nice bit about this is that `text*` is pure, so easily testable. Since `text>!` is constructed, I'm happy not testing it. Since I use Midje prerequisites to test that the `>!`-style functions are called when appropriate, I get nicely decoupled unit tests that don't have to know they're working with agents (except that the `>!` functions always return irrelevant values.) I haven't been using this style for long, but it feels right so far. Latest book: /Functional Programming for the Object-Oriented Programmer/ https://leanpub.com/fp-oo -- -- 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.
Reactive Patterns with Atoms - am I using too much state?
Hey guys, As I start to work on more Clojurescript UI code, I've been running into a pattern with atoms and watches that I THINK I can abstract away... but the solution feels wrong, and I'd love to hear a better way. Say I'm building a stopwatch for timing runners in a race. I've got a clojure record like this: (defrecord StopwatchState [ active? ;; timer running? timestamp ;; UTC time of this particular state stopwatch-time ;; the time on the stopwatch as of "timestamp" results ;; pairs of [athlete number, time]]) and a bunch of functions that toggle the timer, mark an athlete crossing the line, update the timer, etc. My view holds the current state in an atom: (def state (atom ,,some-stopwatch-state)) and I update my views by adding watches to the atom and refreshing the various UI components to match the new state. Now! Here's the annoying pattern. In the cljs UI world, to poke these atoms, I end up wrapping all of my model functions like this: (defn toggle! [] (swap! state toggle)) (defn mark! [athlete-number] (swap! state mark athlete-number)) I can think of two ways to break the pattern. 1) A deep-code-walking macro that transforms code like (mark state athlete-number) into (swap! state mark athlete-number) if the first argument is an atom; 2) a defstatefn macro that defines the "mark" and "mark!" versions at the same time. Both feel wrong. My goal is to program in a more declarative way. Is there a better way to structure UI code? -- Sam Ritchie (@sritchie) Paddleguru Co-Founder 703.863.8561 www.paddleguru.com <http://www.paddleguru.com/> Twitter <http://twitter.com/paddleguru>// Facebook <http://facebook.com/paddleguru> -- -- 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.
Re: big atoms (was Re: STM - a request for "war stories")
> In the epic thread about the STM between Rich and Cliff Click[1] the > main argument against the STM was that it didn't help solve the problem > of where to place guards around the data. From one of Cliff's arguments: > > In a trivial example I can say �go up one call level and atomic > there�, > but in the Real Program � I can�t do that. > Go up how many layers and add atomic? 1 layer? 10 layers? 100 layers? > Yes, I see unique call-stacks > with >100 layers. I can�t put atomic around main because that makes my > program single-threaded. > > > I believe Cliff is arguing here that when a program pushes all of the > state into a single atom where a lot of writes occur that app > effectively is single-threaded. (Please correct me if I am > misunderstanding!) Thoughts? > Actually, this is one of Cliff's weaker points. Note that when he says "atomic", he really means "dosync". He speaks from experience with HotSpot where this was a constant source of bugs. It doesn't translate directly into the same ptifalls with Clojure's STM because 1) Clojure has strict control on what needs a transaction to mutate and 2) the points of mutation are much more focused when you are dealing with immutable structures. Cliff's strongest argument comes from experience with MPI, where he raises very valid points against any implementation of a high-performance concurrent library: This is exactly the trap MPI fell into; and *you* have to do it anyways. > Double-unsmiley. :-( :-( > > Here’s the deal: > > I write a Large Complex Program, one that Really Needs STM to get it >right. >- But performance sucks. >- So I do a deep dive into the STM runtime, and discover it has >warts. >- So I hack my code to work around the warts in the STM. >- Crap like: at an average of 5 cpus in this atomic block the STM >‘works’, but at an average of 7 cpus in the same atomic block I get a >continous fail/retry rate that’s so bad I might as well not bother. So I >guard the STM area with a “5-at-a-time” lock and a queue of threads > waiting >to enter. Bleah (been there; done that – for a DB not an STM but >same-in-priniciple situation). A thousand thousand variations of the same >crap happens, each requiring a different hack to my code to make it >performant. >- Meanwhile the STM author (You: Rich) hacks out some warts & hands me >a beta version. >- I hack my code to match the STM’s new behavior, and discover some >new warts. > > Back & Forth we go – and suddenly: my app’s “performance correctness” is > intimately tied to the exact STM implementation. Any change to the STM’s > behavior kills my performance – and you, Rich, have learned a lot about the > building of a robust good STM. You (now) know the mistakes you made and * > know*it’s time to restart the STM implementation from scratch. > On the other hand, this is a problem occuring only at the most demanding level of load on the code. People may still benefit from the STM to write simple, correct concurrent programs. As I already explained, in my experience atoms cover 98% of that need and locks are still unavoidable. If I wrote a whole system from scratch and based everything on the STM, *then* it could replace locks. This will never happen in a JDK-based Clojure. -- 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
big atoms (was Re: STM - a request for "war stories")
Datomic stores the entire database in an atom (not an STM ref), and updates it with a call to swap! It is literally no more complex than a trivial hackneyed book example. :-) A lot of my systems have evolved into something similar and I've wondered what the implications of this approach are. As more and more state is added to this single atom and with multiple threads performing swap!s (CASs) how will performance be effected? i.e. How will write contention play out in a system designed like this? I'm sure the answer to this depends on the details of the system but at what point does this become a problem? In the epic thread about the STM between Rich and Cliff Click[1] the main argument against the STM was that it didn't help solve the problem of where to place guards around the data. From one of Cliff's arguments: In a trivial example I can say “go up one call level and atomic there”, but in the Real Program – I can’t do that. Go up how many layers and add atomic? 1 layer? 10 layers? 100 layers? Yes, I see unique call-stacks with >100 layers. I can’t put atomic around main because that makes my program single-threaded. I believe Cliff is arguing here that when a program pushes all of the state into a single atom where a lot of writes occur that app effectively is single-threaded. (Please correct me if I am misunderstanding!) Thoughts? -Ben 1. http://www.azulsystems.com/blog/cliff/2008-05-27-clojure-stms-vs-locks -- 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
Re: On using atoms together with side effect functions
On Fri, Jan 6, 2012 at 11:28 PM, Alan Malloy wrote: > but if you look at the post There is no call for taking a rude tone. I correctly answered the question as originally posed. -- 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
Re: On using atoms together with side effect functions
On Jan 6, 7:32 pm, Cedric Greevey wrote: > On Fri, Jan 6, 2012 at 10:22 PM, Alan Malloy wrote: > > On Jan 6, 6:16 pm, Cedric Greevey wrote: > >> On Fri, Jan 6, 2012 at 4:34 PM, Alan Malloy wrote: > >> > On Jan 6, 12:56 pm, Jozef Wagner wrote: > >> >> Thank you, > > >> >> But the things are more complicated. In my case, I need to update the > >> >> atom > >> >> with the result of a (native) function which unfortunately also performs > >> >> some side effects and cannot be split in two. > > >> >> Updated example: > > >> >> (def state {:result nil :input [1 2 3]}) > > >> >> (defn update-item! > >> >> [item] > >> >> (if (:result item) ; if already processed, do nothing > >> >> item > >> >> (let [result (side-effect-fn! (:input item))] > >> >> (assoc item :result result > > >> >> (swap! state update-item!) ;; same problem > > >> > Not doable with atoms if you have a side-effecty thing that you can't > >> > separate out. You'll have to use something lower-level like Java > >> > synchronization or locks. > > >> Or something higher level like transactions. Use a ref and have > >> update! alter the ref, then (send-off some-agent #(spit ...)), inside > >> a dosync. The agent send only goes if the transaction commits. > > > This works exactly as well as with atoms: it works fine if you have a > > pure function and an I/O function, but doesn't work if you have a > > single function that does both pure computation and I/O side effects. > > Jozef has some Java magic that does I/O as a side effect of a > > computation, and he cannot untangle the two. > > Wrong. Jozef has this: > > (def aval (atom {:dumped false :contents "hello world"})) > > (defn update! > [item] > (when-not (:dumped item) > (spit "a.out" (:contents item) :append true) > (assoc item :dumped true))) > > (swap! aval update!) > > Which can be transformed to this: > > (def aval (ref {:dumped false :contents "hello world"})) > > (def aagent (agent nil)) > > (defn update > [item] > (dosync > (if (:dumped @item) > (ref-set item nil) > (do > (alter item assoc :dumped true) > (send-off aagent (fn [_] (do (spit "a.out" (:contents @item) > :append true) nil))) > > (update aval) > > which should have the same semantics, except that the spit cannot be > done twice (or more) for one call to update. That's the simplification he made in his first post, but if you look at the post I was actually replying to he's confessed he actually has a different situation. -- 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
Re: On using atoms together with side effect functions
On Fri, Jan 6, 2012 at 10:22 PM, Alan Malloy wrote: > On Jan 6, 6:16 pm, Cedric Greevey wrote: >> On Fri, Jan 6, 2012 at 4:34 PM, Alan Malloy wrote: >> > On Jan 6, 12:56 pm, Jozef Wagner wrote: >> >> Thank you, >> >> >> But the things are more complicated. In my case, I need to update the atom >> >> with the result of a (native) function which unfortunately also performs >> >> some side effects and cannot be split in two. >> >> >> Updated example: >> >> >> (def state {:result nil :input [1 2 3]}) >> >> >> (defn update-item! >> >> [item] >> >> (if (:result item) ; if already processed, do nothing >> >> item >> >> (let [result (side-effect-fn! (:input item))] >> >> (assoc item :result result >> >> >> (swap! state update-item!) ;; same problem >> >> > Not doable with atoms if you have a side-effecty thing that you can't >> > separate out. You'll have to use something lower-level like Java >> > synchronization or locks. >> >> Or something higher level like transactions. Use a ref and have >> update! alter the ref, then (send-off some-agent #(spit ...)), inside >> a dosync. The agent send only goes if the transaction commits. > > This works exactly as well as with atoms: it works fine if you have a > pure function and an I/O function, but doesn't work if you have a > single function that does both pure computation and I/O side effects. > Jozef has some Java magic that does I/O as a side effect of a > computation, and he cannot untangle the two. Wrong. Jozef has this: (def aval (atom {:dumped false :contents "hello world"})) (defn update! [item] (when-not (:dumped item) (spit "a.out" (:contents item) :append true) (assoc item :dumped true))) (swap! aval update!) Which can be transformed to this: (def aval (ref {:dumped false :contents "hello world"})) (def aagent (agent nil)) (defn update [item] (dosync (if (:dumped @item) (ref-set item nil) (do (alter item assoc :dumped true) (send-off aagent (fn [_] (do (spit "a.out" (:contents @item) :append true) nil))) (update aval) which should have the same semantics, except that the spit cannot be done twice (or more) for one call to update. -- 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
Re: On using atoms together with side effect functions
On Jan 6, 6:16 pm, Cedric Greevey wrote: > On Fri, Jan 6, 2012 at 4:34 PM, Alan Malloy wrote: > > On Jan 6, 12:56 pm, Jozef Wagner wrote: > >> Thank you, > > >> But the things are more complicated. In my case, I need to update the atom > >> with the result of a (native) function which unfortunately also performs > >> some side effects and cannot be split in two. > > >> Updated example: > > >> (def state {:result nil :input [1 2 3]}) > > >> (defn update-item! > >> [item] > >> (if (:result item) ; if already processed, do nothing > >> item > >> (let [result (side-effect-fn! (:input item))] > >> (assoc item :result result > > >> (swap! state update-item!) ;; same problem > > > Not doable with atoms if you have a side-effecty thing that you can't > > separate out. You'll have to use something lower-level like Java > > synchronization or locks. > > Or something higher level like transactions. Use a ref and have > update! alter the ref, then (send-off some-agent #(spit ...)), inside > a dosync. The agent send only goes if the transaction commits. This works exactly as well as with atoms: it works fine if you have a pure function and an I/O function, but doesn't work if you have a single function that does both pure computation and I/O side effects. Jozef has some Java magic that does I/O as a side effect of a computation, and he cannot untangle the two. -- 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
Re: On using atoms together with side effect functions
On Fri, Jan 6, 2012 at 4:34 PM, Alan Malloy wrote: > On Jan 6, 12:56 pm, Jozef Wagner wrote: >> Thank you, >> >> But the things are more complicated. In my case, I need to update the atom >> with the result of a (native) function which unfortunately also performs >> some side effects and cannot be split in two. >> >> Updated example: >> >> (def state {:result nil :input [1 2 3]}) >> >> (defn update-item! >> [item] >> (if (:result item) ; if already processed, do nothing >> item >> (let [result (side-effect-fn! (:input item))] >> (assoc item :result result >> >> (swap! state update-item!) ;; same problem > > Not doable with atoms if you have a side-effecty thing that you can't > separate out. You'll have to use something lower-level like Java > synchronization or locks. Or something higher level like transactions. Use a ref and have update! alter the ref, then (send-off some-agent #(spit ...)), inside a dosync. The agent send only goes if the transaction commits. -- 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
Re: On using atoms together with side effect functions
On Jan 6, 12:56 pm, Jozef Wagner wrote: > Thank you, > > But the things are more complicated. In my case, I need to update the atom > with the result of a (native) function which unfortunately also performs > some side effects and cannot be split in two. > > Updated example: > > (def state {:result nil :input [1 2 3]}) > > (defn update-item! > [item] > (if (:result item) ; if already processed, do nothing > item > (let [result (side-effect-fn! (:input item))] > (assoc item :result result > > (swap! state update-item!) ;; same problem Not doable with atoms if you have a side-effecty thing that you can't separate out. You'll have to use something lower-level like Java synchronization or locks. -- 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
Re: On using atoms together with side effect functions
Thank you, But the things are more complicated. In my case, I need to update the atom with the result of a (native) function which unfortunately also performs some side effects and cannot be split in two. Updated example: (def state {:result nil :input [1 2 3]}) (defn update-item! [item] (if (:result item) ; if already processed, do nothing item (let [result (side-effect-fn! (:input item))] (assoc item :result result (swap! state update-item!) ;; same problem Jozef -- 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
Re: On using atoms together with side effect functions
On Fri, Jan 6, 2012 at 3:02 PM, Jozef Wagner wrote: > Consider this contrived piece of code: > > (def aval (atom {:dumped false :contents "hello world"})) > > (defn update! > [item] > (when-not (:dumped item) > (spit "a.out" (:contents item) :append true) > (assoc item :dumped true))) > > How should I correctly call update! ? Each of following two calls have > drawbacks. > > (swap! aval update!) ;; update! can be called more than once > > (let [new-val (update! aval)] > ;; aval can be changed in between from other thread > (reset! aval new-val)) > > Best, > Jozef > Jozef, I think you can solve this by adding a little more info and keeping the update function and side effects separate: (def aval (atom { :contents "hello world" })) (defn update-item [{:keys [dumped] :as item}] (assoc item :dumped true :needs-dump (not dumped))) (let [{:keys [needs-dump contents]} (swap! aval update-item)] (if needs-dump (spit "a.out" contents :append true))) Whoever gets to aval first while it hasn't been dumped will see needs-dump as true and write the file. Depending on your requirements, if the file write fails, you'll might need to do some extra work to put aval back in a state consistent with reality. Hope this helps, Dave -- 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
On using atoms together with side effect functions
Consider this contrived piece of code: (def aval (atom {:dumped false :contents "hello world"})) (defn update! [item] (when-not (:dumped item) (spit "a.out" (:contents item) :append true) (assoc item :dumped true))) How should I correctly call update! ? Each of following two calls have drawbacks. (swap! aval update!) ;; update! can be called more than once (let [new-val (update! aval)] ;; aval can be changed in between from other thread (reset! aval new-val)) Best, Jozef -- 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
Re: working with agents and atoms - a beginner question
After reading your posts and thinking "wouldn't it be nice to just kick off a thread and not care about the return value" I recall Rich using/liking [1] the Java Executor framework [2]. I looked at clojure.lang.Agent and saw it used there, too. It's tricky because I wouldn't want to lean on Java too much for something this fundamental or go too far without expecting to have to code something as complicated as what's found in core.clj (with possible java mechanics as found in RT.java). I picture wanting a system that can kick off workers (Executor framework) that only needs start() and join() semantics. I haven't gone through all the Executor and related stuff yet so I still need to read about everything that's available. - - - [1] http://clojure.org/concurrent_programming [2] http://www.ibm.com/developerworks/java/library/j-jtp1126.html On Wed, Jun 16, 2010 at 3:51 PM, Meikel Brandmeyer wrote: > Hi, > > Am 16.06.2010 um 22:34 schrieb Christophe Grand: > >> I agree, it still feels a little dirty to use a future without caring >> about the return value but on the positive said you get an easy way to >> block and wait for the tread to finish (deref) and you also get >> future-done?, future-cancel and future-cancelled which can prove >> useful. > > True. This infrastructure is an incentive to use future. Maybe one can wash > away the dirty feeling by believing, that deref'ing is actually a > syncronisation point of sorts and the return value just a "side-effect". > > Sincerely > Meikel > > -- > 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 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
Re: working with agents and atoms - a beginner question
Hi, Am 16.06.2010 um 22:34 schrieb Christophe Grand: > I agree, it still feels a little dirty to use a future without caring > about the return value but on the positive said you get an easy way to > block and wait for the tread to finish (deref) and you also get > future-done?, future-cancel and future-cancelled which can prove > useful. True. This infrastructure is an incentive to use future. Maybe one can wash away the dirty feeling by believing, that deref'ing is actually a syncronisation point of sorts and the return value just a "side-effect". Sincerely Meikel -- 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
Re: working with agents and atoms - a beginner question
On Wed, Jun 16, 2010 at 10:20 PM, Meikel Brandmeyer wrote: > The typical solution for your problem would probably be: > > (->> long-running-function-with-recur Thread. .start) > > This starts you function in a dedicated thread and you can save the overhead > of send-off and use recur directly. I'm unsure about using future here. For > me future is a thing, which returns something. Using it for a process which > does return something useful seems "dirty" to me. I agree, it still feels a little dirty to use a future without caring about the return value but on the positive said you get an easy way to block and wait for the tread to finish (deref) and you also get future-done?, future-cancel and future-cancelled which can prove useful. Christophe -- European Clojure Training Session: Brussels, 23-25/6 http://conj-labs.eu/ Professional: http://cgrand.net/ (fr) On Clojure: http://clj-me.cgrand.net/ (en) -- 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
Re: working with agents and atoms - a beginner question
Hi, Am 15.06.2010 um 23:27 schrieb Ryan Waters: > Thank you for pointing that out. I notice your style is similar to > Rich's in his ant.clj [1] which seems like the kind of solution that > might be used in other functional and/or lisp languages. Do you know > if that's the case with self-calling functions and agents? However, > isn't there more overhead with calls to send-off instead of recur? Yes, there is additional overhead. However hijacking a thread from agent thread pool (even if send-off) is misusing agents as Christophe said. Agents is about updating states. Not about (long running) threads. The typical solution for your problem would probably be: (->> long-running-function-with-recur Thread. .start) This starts you function in a dedicated thread and you can save the overhead of send-off and use recur directly. I'm unsure about using future here. For me future is a thing, which returns something. Using it for a process which does return something useful seems "dirty" to me. > I understand functions sent to an agent will only run one at a time, > fifo-style, but was under the impression *agent* was for the current > "main" thread of the program. Does *agent* instead refer to whatever > is the current thread in the function's runtime context? Hope that > question makes sense. *agent* is bound to the agent whose action we are currently running in this thread. So concurrently running actions see different *agent*s. Hope this helps. Sincerely Meikel -- 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
Re: working with agents and atoms - a beginner question
On Wed, Jun 16, 2010 at 12:17 AM, Christophe Grand wrote: > Hi Ryan, > > On Tue, Jun 15, 2010 at 6:01 PM, Ryan Waters wrote: >> I'm working with the code at the following gist and also pasted below: >> >> http://gist.github.com/421550 >> >> I'd like to have execution of a separate thread (agent) continue >> running until it sees the atom 'running' change to false. >> >> Unfortunately, the program doesn't return from the send-off but >> to my understanding it should. Why won't it return? I'm using >> clojure 1.1. > > It does return from send-off -- in your gist's version at last thanks > to Shawn but there are still other errors. > >> (ns nmanage) >> >> (def running (atom true)) >> >> (defn process >> [] > > A fn sent as an action to an agent must accept at least one arg: the > agent's current value (if additional args are passed to args, the > action fn must accept them too). So the above line should be [_] (_ to > signify that you don't care about the value) instead of [] > Thank you - I was unaware that a function sent to an agent had to accept at least one arg. >> (when @running >> (prn "hi") >> (Thread/sleep 1000)) >> (recur)) > > Here your recur is misplaced, you want to recur when @running is true > so the (recur) should be at the end of the when form and it should > have an extra argument since we changed process to take one arg. > However this when/recur pattern is what the while macro expands to. > > (defn process [_] > (while @running > (prn "hi") > (Thread/sleep 1000))) > Very true - in this example, I totally agree. The example I put together is a simplified version of the program I'm working on which uses some file I/O. I'm wanting to tail a file and process its contents over time so I had a loop that would read the file until it started reading 'nil', then sleep, then try again, creating a loop within a loop (and polling the file for new contents). In trying to keep the example program faithful to the other, I ended up with some nonsensical clojure ; ) > >> ;;; >> (send-off (agent nil) (process)) > > Here it should be (send-off (agent nil) process) but Shawn already > pointed this out. > > I think that using an agent and not caring about its value is kind of > an abuse, better use a future. > > (def running (atom true)) > > (future > (while @running > (prn "hi") > (Thread/sleep 1000))) > Here my near total ignorance of futures comes into play. Thank you very much for pointing this out as a better way. I've been so eager to write a first program in clojure that I haven't gotten through all the 1.1 (and 1.0) language features yet. :D > ;;; > (do > (prn "this prints now - fixed thanks to Shawn Hoover") > (Thread/sleep 2000) > (reset! running false)) > > hth, > > Christophe > > -- > European Clojure Training Session: Brussels, 23-25/6 http://conj-labs.eu/ > Professional: http://cgrand.net/ (fr) > On Clojure: http://clj-me.cgrand.net/ (en) > I appreciate yours and everyone's valuable time! -- 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