Reputation: 59
I'm learning Clojure to use it with Quil to make generative art and I would like to try to understand a bit more about let function and reader macro probably.
I tried reading about reader macros from the docs but I couldn't find a clear answer to it.
I currently have this piece of code:
(let [dabs (take 10 (repeatedly #(make-watercolor
(mkpt
(randomNormal 0.1 0.9)
(randomNormal 0.1 0.9))
(w (randomNormal 0.4 0.7)))))]
(draw-multiple-watercolor dabs 3))
Which is pretty ugly and not really readable. I would like to slim down the repeated function splitting it into smaller pieces, but since those pieces will be evaluated multiple times and has random inside them I cannot store their result inside a variable and use that, instead I need to evaluate those when needed.
My question is: is there a way to do something like this
(let [randCoord (randomNormal 0.1 0.9) ;This..
randPoint (mkpt randCoord randCoord) ;..and this doesn't should be evaluated here, but on the repeatedly function calls
dabs (take 10 (repeatedly #(make-watercolor
randPoint ;Evaluation here
(w (randomNormal 0.4 0.7)))))]
(draw-multiple-watercolor dabs 3))
Upvotes: 1
Views: 92
Reputation: 16194
One option is to use the same approach you've used with the function you pass to repeatedly
: just wrap the expressions in functions that take no arguments (or only the args you want to change), then they'll be evaluated each time you invoke the function.
(let [rand-coord (fn [] (randomNormal 0.1 0.9)) ;; or #(randomNormal 0.1 0.9)
make-dab #(make-watercolor (mkpt (rand-coord) (rand-coord))
(w (randomNormal 0.4 0.7)))
dabs (take 10 (repeatedly make-dab))]
(draw-multiple-watercolor dabs 3))
Also take a look at letfn
for defining functions in a non-top-level/namespace scope.
You might also find threading macros like ->
, ->>
, as->
, some->
, cond->
, etc. can make some code more readable. For example, if you changed draw-multiple-watercolor
to take its sequence of dabs last (which is fairly common practice for functions that operate on sequences in Clojure) then you could do something like this:
(let [rand-coord (fn [] (randomNormal 0.1 0.9)) ;; or #(randomNormal 0.1 0.9)
make-dab #(make-watercolor (mkpt (rand-coord) (rand-coord))
(w (randomNormal 0.4 0.7)))]
(->> make-dab
(repeatedly 10) ;; note: repeatedly can take a # of iterations
(draw-multiple-watercolor 3)))
Upvotes: 3