What is the best way to iterate over state in Clojure (monad?)

I just wrote this code:

(defn parameters [transform-factory state] (lazy-seq (let [[r1 state] (uniform state) [r2 state] (uniform state) [t state] (transform-factory state)] (cons [t [r1 r2]] (parameters transform-factory state))))) (defn repeated-transform [mosaic n transform-factory state] (reduce transform-square mosaic (take n (parameters transform-factory state)))) 

The parameters function generates a lazy sequence of values ​​generated from state , which are used to parameterize the re-conversion of something (in this case, a "mosaic").

it seems to me that parameters shows a fairly common pattern that occurs when you have some state that needs to be transferred (in this case, to generate random values). is there a name for this?

is there a better way to write the first function? related problems can often be solved with reduce , which “transfers” the state, but here I have nothing to reduce. likewise, reductions don't seem to fit. is this a good example for a monad? (from the theoretical pov I don’t see how you determine the way of combining several copies into one, but maybe this does not change the practical application - it seems that such problems of the monad are solved in another place where some state needs to be carried around).

(ps mentions random numbers, but I can't replace this with a solution that uses a volatile state behind the scenes - like "normal" random procedures - for reasons not related to the question).

+7
source share
3 answers

Of course, you can look at the state monad to make sure that it suits you.

General guidelines for using monads:

  • Sequential execution (operations with the pipeline)
  • Reprocessing modular side effects (e.g. error handling / logging / status)
  • Keep your business logic clean with clean features.

Some resources on the monk that I found very useful (for Clojure),

Adam Bow: Introduction to Monads (video) http://www.youtube.com/watch?v=ObR3qi4Guys

and Jim Duilly: Monads at Clojure http://www.clojure.net/2012/02/02/Monads-in-Clojure/

+4
source

[answering myself, as this is the best solution I've found so far]

you can rewrite the above as a fold over functions. therefore, the functions become data, the state is “passed”, and the function used applies each function in turn to the state and accumulates the result.

I don’t see an elegant way to implement this: the function that develops seems to be “new”, and you need an additional template application for adding / separating state and battery - so I wrapped the whole process in a function called fold-over . source here and an example of the function used here .

+3
source

Something you should check out is -> and ->> , streaming macros.

Instead of this code:

 (let [state (dosomething state) state (dosomethingelse state) state (dolastthing state)] state) 

You can write:

 (-> state (dosomething) (dosomethingelse) (dolasttthing)) 

which "streams" pass through functions, eventually returning them.

Now your code doesn't exactly match what I wrote. The way I guess can follow it was if your functions took and returned hashmaps. that is, (uniform state) can return {:state state-val :r1 r1-val} .

Then you can rewrite your code as follows:

 (->> {:state state} (merge uniform) (merge uniform) (transform-factory)) 

Much nicer! :)

+3
source

All Articles