Hi All, I was working on a music notation issue with my music libraries Pink and Score and came upon a solution I thought was curious. It certainly solved a real problem I had with delayed function calls, and I thought maybe others might find a use for it too.
The scenario I had is that in writing events, I needed to find a way to have certain arguments be dynamic at the time of application of the function, rather than the time of event creation. For example: [fm 2.5 0.3 (env [0.0 500 0.5 1000]) 0.3] when processed by Score and Pink, would yield an event data structure where the 3rd argument to the fm function would be a stateful function generated by (env ...). That would be fine if that the event was used once, but if the event was reused (i.e. I want to listen to that block of score again...), the function returned by (env) would have already been processed. The code I came up with is at [1]. It allowed so that I could use: [fm 2.5 0.3 (!*! env [0.0 500 0.5 1000]) 0.3] and everytime the fm was applied, the code within the !*! was run at apply time. This ends up using the apply!*! function from [1] instead of apply to resolve that argument when applying the fm function. I found this curious as it meant that I didn't have to write a new wrapper function just to dynamically create arguments to call the fm function, such as: [#(fm 0.3 (env [0.0 500 0.5 1000]) 0.3) 0.25] which seemed a bit more noisy and less clear to the intent of the event code. I tried to think of a more general scenario where this might be useful. I came up with two examples, the first was composing a logging function: user=> (def logger (partial apply!*! println "[" (!*! #(str (new java.util.Date))) "]")) #'user/logger user=> (logger "testing2") [ Tue Dec 02 22:22:44 EST 2014 ] testing2 nil user=> (logger "testing3") [ Tue Dec 02 22:22:50 EST 2014 ] testing3 Not too exciting, I know. On the other hand, I thought about FRP, and came up with: user=> (defn r!*! [func & args] #_=> (reify IDeref #_=> (deref [_] (apply!*! func args))) #_=> ) #'user/r!*! user=> (def a (atom 45)) #'user/a user=> (def b (r!*! * (!*! deref a) 10)) #'user/b user=> @a 45 user=> @b 450 user=> (reset! a 50) 50 user=> @b 500 user=> (def c (r!*! + (!*! deref b) 6)) #'user/c user=> @c 506 user=> (reset! a 10) 10 user=> @a 10 user=> @b 100 user=> @c 106 I thought the notation of the r!*! reactive cells above looked nice to write, and using IDeref captured a bit of the idea of working with time-varying values. That could also be a little clearer with: user=> (def sig (partial !*! deref)) #'user/sig user=> (def c (r!*! + (sig b) 6)) #'user/c user=> @c 106 The code at [1] is pretty small, but seemed to open up a number of interesting ways to express things that I hadn't thought about before in terms of apply-time of functions. Any feedback/comments/advice very welcome! Thanks! steven [1] - https://github.com/kunstmusik/pink/blob/master/src/pink/util.clj#L9-L29 -- 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.