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.

Reply via email to