Hello, To be honest I don't see any fundamental difference between your first attempt and the improvement: both share the fact that the mutation of the state happens within the draw function. So in both cases, you have a temporal coupling between updating the state of the app and rendering a new view of the app's state.
I would suggest that you don't swap! at all within draw, just deref and render the result of the dereffing. And, in another thread, at potentially a totally different pace than the redrawing's pace, update the application's state accordingly to business rules / constraints. Schematically, something like this: (def app-state (atom (init-state))) (defn draw [...] (let [app-snapshot (deref app-state)] ... call quil primitives to render the application state snapshot ...)) (future ... logic which updates the app-state atom depending on business rules / constraints, in a separate thread ...) HTH, -- Laurent 2014-03-09 13:47 GMT+01:00 J. Pablo Fernández <pup...@pupeno.com>: > Hello Clojurians, > > I'm starting to play with Processing and I want to use my favorite > programming language for it, so I started using > Quil<https://github.com/quil/quil>. > The problem is that Processing has a imperative architecture and makes my > Clojure code look bad. For those that don't know Processing/Quil, here's a > little overview that's relevant to this email. > > Processing is a language and a library that makes it easy to draw on the > screen to do generative art, simulations, etc. Processing programs have two > methods, a setup method that is run once, at the beginning, and then a draw > method that is run over and over. Literally something like: > > Walker w; > > void setup() { > w = new Walker(); > } > > void draw() { > w.render(); > w.walk(); > } > > I'm using a hypothetical walker, an entity that walks around the screen. > More or less taken from here: http://natureofcode.com/book/introduction/ > > My understanding is that the equivalent Clojure code using Quil would look > like this: > > (defn setup [] > (set-state! :walker (atom (create-walker)))) > > (defn draw [] > (render-walker @(state :walker)) > (swap! (state :walker) walk)) > > Quil stores a map in the meta-data of the Processing applet and let's you > access it. Since I need the state to change, I'm storing the walker in an > atom. I found examples out there following more or less this structure. I'm > not happy with this structure, it doesn't feel functional enough. > > When thinking about this, I got reminded of Erlang processes, specially > with OTP, where you have a function that's called over and over to which > the state is passed and which returns the next state. Following that > structure I would like to implement it like this: > > (defn setup [] > [(create-walker)]) > > (defn draw [walker] > (render-walker walker) > [(walk walker)]) > > The result of calling setup is a vector containing the attributes to draw, > and the result of draw is a vector containing the attributes that will be > used in the next call to draw. > > Does this make sense? Does it look cleaner to you guys? > > I achieved that by writing this wrappers for setup and draw: > > (defn setup-wrapper [] > (set-state! :state (atom (setup)))) > > (defn draw-wrapper [] > (swap! (state :state) > (fn [s] (apply draw s)))) > > My concern with this is that now the whole state is in one single atom > that I'm replacing on each frame and that might not be good. Is it copying > the whole state or can Clojure use its copy-on-demand feature even for > atoms? Is there a better way of doing this? > > 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. > -- 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.