2012-04-26 6 views
7

Ho appena scritto questo codice:Come iterare meglio nel corso Stato in Clojure (Monade?)

(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)))) 

la funzione parameters genera una sequenza pigro di valori generati dal state, che vengono utilizzati per parametrizzare una trasformazione ripetuto di qualcosa (un "mosaico" in questo caso).

mi sembra che parameters mostri uno schema abbastanza comune che emerge quando si dispone di un po 'di state che deve essere portato in giro (in questo caso per generare valori casuali). C'è un nome per questo?

c'è un modo migliore per scrivere la prima funzione? problemi correlati possono spesso essere risolti con reduce, che "porta avanti" lo stato, ma qui non ho nulla da ridurre. allo stesso modo, reductions non sembra adattarsi. questo è un buon caso per una monade? (da un pov teorico non vedo come tu definisca un modo per combinare più istanze in una, ma forse non cambia l'applicazione pratica - sembra il tipo di problema che le monadi risolvono altrove, dove alcuni stati devono essere portato in giro).

(ps ho menzionato i numeri casuali, ma non posso sostituirlo con una soluzione che utilizza lo stato mutevole dietro le quinte - come fanno le normali routine casuali - per ragioni estranee alla domanda).

+0

> (ps ho menzionato i numeri casuali, ma non posso sostituirlo con una soluzione che utilizza lo stato mutabile dietro le quinte - come fanno le "normali" routine casuali - per ragioni estranee alla domanda). Si potrebbe usare a) un generatore pseudo-casuale che trasporta un seme intorno, o b) copia lo stato mutabile (in modo che non sia mutabile). Ho adottato questo approccio per l'implementazione [puro mersenne twister] [1]. [1]: http://hackage.haskell.org/package/mersenne-random-pure64-0.2.0.3 –

+0

Sono venuto qui per fare la stessa domanda – jes5199

+0

@DonStewart - non capisco come sarebbe cambia quello che sto chiedendo. in effetti, quello che sto facendo è copiare lo stato - questo è lo stato '' '' in alto 'e la fonte dei miei problemi. –

risposta

4

Si potrebbe certamente guardare la monade di stato per vedere se è una buona misura per voi.

linee guida generali da utilizzare monadi sono:

  • sequenziale di esecuzione (operazioni di gasdotti)
  • riutilizzabile lato modulare effetto di elaborazione (es: la gestione degli errori/logging/ statali)
  • mantenere la vostra logica di business pulito in pura funzione

Alcune risorse sulle monadi che ho trovato molto utili (per Clojure) sono

Adam Smyczek: Introduzione al Monadi (Video) http://www.youtube.com/watch?v=ObR3qi4Guys

e Jim Duey: Monadi in Clojure http://www.clojure.net/2012/02/02/Monads-in-Clojure/

+0

grazie - avrò uno sguardo. speravo che questo fosse un problema ben noto ma apparentemente no, così ho il cookie "migliore risposta": o) –

3

[me rispondere, dal momento che questa è la soluzione migliore che ho trovato finora ]

è possibile riscrivere quanto sopra come una piega sulle funzioni. quindi le funzioni diventano dati, lo stato è "passato attraverso" e la funzione utilizzata applica a turno ciascuna funzione allo stato e accumula il risultato.

Non riesco a vedere un modo elegante per implementare questo - la funzione che è piegata sembra essere "nuova" e hai bisogno di un ulteriore foglio di calcolo per aggiungere/separare lo stato e l'accumulatore - così ho avvolto l'intero processo in una funzione chiamato fold-over. il source is here e an example of the function in use is here.

+0

questo mi sembra vicino. Sembra che forse questo approccio con alcune macro potrebbe trasformarsi in un "let" di piegatura, e forse sarebbe utile. – jes5199

+0

sì, dopo ho bisogno di conoscere le macro in clojure ... –

3

Qualcosa da controllare è -> e ->>, i macro di threading.

Invece di codice come questo:

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

si può scrivere:

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

in cui si afferma "discussioni", attraverso le funzioni, eventualmente restituirlo.

Ora, il tuo codice non segue esattamente quello che ho scritto. Il modo in cui immagino potrebbe seguirlo è stato se le tue funzioni hanno preso e restituito hashmaps. Ad esempio (stato uniforme) potrebbe restituire {:state state-val :r1 r1-val}.

Allora si potrebbe riscrivere il codice come questo:

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

Molto più bello! :)

+0

oooh. Grazie! lo guarderò. suona bene. –