It sounds like you're running into the chunked sequence behavior of map (it's lazy but it realizes chunks of the sequence for efficiency rather than strictly on-demand).
I'd say the possibilities are: don't use side-effecting functions in your monads or define a fully lazy version of map and define m-plus in terms of that? Sean On Tue, Oct 22, 2013 at 4:23 AM, Mark Fisher <[email protected]> wrote: > I originally posted this in Stack Overflow, but realised I might get more > response from the google group. Apologies for duplication. > > I'm seeing some issues using a parser monad created from the state monad > transformer. > > I've written a full test case on the SO page outlining the issue, which is > that when I use m-plus for the combined monad, it always evaluates the first > 2 methods, even though it uses the return values from the first (if it is > valid), and any state changes in the second occur but are discarded (however > side effects do - like d/b updates etc). > > e.g. > > (def parser-m (state-t maybe-m)) > (def world-destroyer > (domonad parser-m > [_ (fetch-state) > result (m-plus > (check-we-are-chilled) > (destroy-planet))] > result)) > (world-destroyer {:chill-out true}) > > In this implementation, destroy-planet is always evaluated. > Both of these monadic functions can terminate by using a :when condition on > the state. > > If I add a dummy method to the m-plus call list at the start (as first or as > second method in list) that does nothing (using a :when nil predicate to > stop its evaluation), the results are fine, no planet is destroyed because > it's never called, and the dummy monadic function takes the hit of stopping > m-plus spilling into the destroy-planet function. > > Interestingly, any state changes I make in the method erroneously called do > not get reflected in the final return value (clearly due to immutability of > the state map), but side effects are happening - and that's my issue. > > I've reverted to using a hand-crafted parser-m as given on Jim Duey's monad > blog which doesn't exhibit this behaviour. > > I'm relatively inexperienced with clojure and monads (I was using this as an > excuse to learn them both), so I thought i'd try and work out why it's > happening. > > From looking at the definitions of state-t monad-m, the only thing i can see > m-plus doing different to Jim's version is: > > state-t monad-m: > (defn x [s] > (apply (fn [& xs] > (first (drop-while nil? xs))) > (map #(% s) flist))) > > jim's: > (defn y [s] > (first (drop-while nil? > (map #(% s) flist)))) > > for some list of functions flist, e.g. > (def flist > [(fn [x] > (println "f a : " x) > (when-let [r (:a x)] r)) > (fn [x] > (println "f b: "x) > (when-let [r (:b x)] r)) > (fn [x] > (println "f nil : " x) > nil)]) > > (x {:b 2}) > (y {:b 2}) > > and running either of these produces same result (2), however they both > produce the println side effects of all 3 functions in the list, so now i'm > even more confused. > > I thought everything in y is lazy, so only the first two methods would be > used from the array. I can't find anything saying apply is lazy, so thought > I was getting closer. > > Anyone have any thoughts on this? Am I using m-plus in the right way inside > a domonad call? > > Cheers, > Mark > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to [email protected] > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > [email protected] > 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 [email protected]. > For more options, visit https://groups.google.com/groups/opt_out. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880) -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] 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 [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
