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.

Reply via email to