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 <[email protected]<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 [email protected]<javascript:>
>> 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] <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 [email protected] <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 [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.