The state modifications are both happening, if i inspect it after the 2nd function does an update the change is there, but the wind out of the return value from the first function is a different object, and immutability is giving me it before the 2nd update, which is a discarded object.
I am seeing the cache get read (fn 1 - returns a value), and then immediately the live fetch (fn 2) which should only happen if the cache hit failed (fn 1). If I put a filler monad function at the front of the queue, then this doesn't happen. So: (m-plus filler mfn1 mfn2) works, as in, mfn2 does *not* get called if mfn1 returns a value. but (m-plus mfn1 mfn2) does call both functions. and all the filler function does is: (def filler (domonad parser-m [:when nil] nil)) If I go with Jim Duey's version of the parser monad (which is hand written and not created through the state-t transform), then I don't need the filler function at all, (m-plus mfn1 mfn2) works as expected - when mfn1 returns a value, mfn2 is not called. This is all with or without debug, i can swap the 2 in and out for each other easily and the problem happens in the transform case, not in hand-crafted case, with no other changes than changing the definition of the parser-m. I think there's a subtle flaw in resultant tranformed monad of (state-t maybe-m) but my clojure-foo is lacking in working out exactly what. I do believe it's supposed to work as I'm trying to use it Mark On Tuesday, 22 October 2013 22:35:59 UTC+1, Ben wrote: > > based on what you posted to stack overflow I would guess it's because the > side-effects (the prints) are coming too soon---you have a println as the > first line of check-k-v, so if the expression (mplus (check-k-v ...) > (check-k-v ...)) is evaluated, then, given that mplus is not a macro, both > arguments will be evaluated, and both prints will happen. > > Since the state modifications aren't both happening, I assume that the > actual computation returned---the domonad block---is being correctly > treated. > > > On Tue, Oct 22, 2013 at 4:23 AM, Mark Fisher <mark.j...@gmail.com<javascript:> > > wrote: > >> I originally posted this in Stack >> Overflow<http://stackoverflow.com/questions/19505334/clojure-algo-monad-strange-m-plus-behaviour-with-parser-m-why-is-second-m-plus>, >> >> 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 <http://www.intensivesystems.net/tutorials/monads_101.html> 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 clo...@googlegroups.com<javascript:> >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> 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 clojure+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/groups/opt_out. >> > > > > -- > Ben Wolfson > "Human kind has used its intelligence to vary the flavour of drinks, which > may be sweet, aromatic, fermented or spirit-based. ... Family and social > life also offer numerous other occasions to consume drinks for pleasure." > [Larousse, "Drink" entry] > > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com 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 clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.