2012-04-26 15 views
7

Właśnie napisał ten kod:Jak lepiej iteracyjnego państwa w Clojure (monady?)

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

funkcja parameters generuje leniwy sekwencji wartości generowanych z state, które są wykorzystywane do parametryzacji powtórzoną transformację czegoś ("mozaika" w tym przypadku).

Wydaje mi się, że parameters pokazuje dość powszechny wzór, który pojawia się, gdy masz jakieś state, które muszą być przenoszone (w tym przypadku do generowania losowych wartości). czy jest na to nazwa?

Czy istnieje lepszy sposób na napisanie pierwszej funkcji? podobne problemy można często rozwiązać za pomocą reduce, które "przenoszą" stan, ale tutaj nie mam nic do zredukowania. podobnie, reductions wydaje się nie pasować. czy to jest dobre dla monady? (z teoretycznego pov nie rozumiem, jak definiujesz sposób łączenia wielu instancji w jedno, ale być może to nie zmienia praktycznego zastosowania - wydaje się, że takie monady rozwiązują gdzie indziej, gdzie niektóre państwa muszą być noszonym dookoła).

(ps wymieniłem losowe liczby, ale nie mogę zastąpić tego rozwiązaniem, które wykorzystuje zmienny stan za kulisami - jak robią to "normalne" losowe rutyny - z przyczyn niezwiązanych z pytaniem).

+0

> (ps wymieniłem losowe liczby, ale nie mogę zastąpić tego rozwiązaniem, które wykorzystuje zmienny stan za kulisami - jak robią "normalne" losowe rutyny - z powodów niezwiązanych z pytaniem). Możesz użyć a) pseudolosowego generatora przenoszącego ziarno dookoła lub b) skopiuj stan zmienny (aby nie można było go zmienić). Zastosowałem to podejście do implementacji [czystego mersenne twister] [1]. [1]: http://hackage.haskell.org/package/mersenne-random-pure64-0.2.0.3 –

+0

Przyszedłem tutaj, aby zadać to samo pytanie – jes5199

+0

@DonStewart - nie rozumiem, jak to by zmień to, o co pytam. w rzeczywistości to, co robię, to kopiowanie stanu - oto, czym jest "stan" powyżej i źródło moich problemów. –

Odpowiedz

4

Z pewnością można spojrzeć na monadę stanu, aby sprawdzić, czy jest ona dla ciebie odpowiednia.

ogólne wytyczne korzystania z monady są:

  • sekwencyjne wykonanie (operacje rurociągów)
  • wielokrotnego użytku modułowe strona przetwarzania efekt (ex: obsługa błędów/rejestrowanie/ państwowe)
  • Zachowaj swoją logikę biznesową czyste w czystych funkcjach

Niektóre zasoby na monadach, które uważam za bardzo użyteczne (dla Clojure) to:

Adam Smyczek: Wprowadzenie do monad (Video) http://www.youtube.com/watch?v=ObR3qi4Guys

i Jim Duey: Monady w Clojure http://www.clojure.net/2012/02/02/Monads-in-Clojure/

+0

dzięki - będę wyglądać. miał nadzieję, że to jest dobrze znany problem, ale najwyraźniej nie, więc mam ciastko "najlepszej odpowiedzi": o) –

3

[odpowiadając na siebie, ponieważ jest to najlepsze rozwiązanie znalazłem do tej pory ]

możesz przepisać powyższe dane jako składane przez funkcje. więc funkcje stają się danymi, stan jest "przekazywany", a użyta funkcja stosuje kolejno każdą funkcję do stanu i akumuluje wynik.

Nie widzę eleganckiego sposobu na wprowadzenie tej funkcji - funkcja, która jest złożona, wydaje się być "nowa" i potrzebujesz dodatkowego zestawu do dodania/odseparowania stanu i akumulatora - więc zawinąłem cały proces w funkcji o nazwie fold-over. source is here i an example of the function in use is here.

+0

to czuje się blisko mnie. Wydaje się, że może to podejście z niektórymi makrami może zmienić się w składanie 'let', a może byłoby to przydatne. – jes5199

+0

tak, dalej muszę się nauczyć o makrach w clojure ... –

3

Coś, co należy sprawdzić to -> i ->>, makra wątków.

Zamiast kodu tak:

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

Można napisać:

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

który "nici" stan pomiędzy funkcjami, ostatecznie zwrot.

Twój kod nie odpowiada dokładnie temu, co napisałem. Sposób, w jaki wyobrażam sobie, że może to nastąpić, był taki, że twoje funkcje zajęły i powróciły. tj. (stan jednolity) może zwrócić {:state state-val :r1 r1-val}.

Następnie można przepisać kod tak:

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

dużo ładniejszy! :)

+0

oooh. dzięki! na to popatrzy. Brzmi dobrze. –