-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add atomic modify+get to MonadState #120
Conversation
Codecov Report
@@ Coverage Diff @@
## master #120 +/- ##
==========================================
+ Coverage 89.82% 90.16% +0.34%
==========================================
Files 66 66
Lines 580 590 +10
Branches 2 2
==========================================
+ Hits 521 532 +11
+ Misses 59 58 -1
Continue to review full report at Codecov.
|
@kailuowang could you take a look? Do you think we should add any laws for this? |
I am on vacation at the time. Will take a proper look once I am back to my computer. In the mean time please feel free to ping other maintainers if you want quick feedback. |
Sure, enjoy your vacation :) @LukaJCB if you have a moment... |
Looks good to me thus far, though I wonder what practical implications this has. I don't think we can actually guarantee that these are implemented atomically, can we? |
@LukaJCB it basically boils down to the fact that the current methods on MonadState don't include one that'd correspond to Ref's modify (modify on MonadState is update on Ref), so using e.g. meow-mtl to derive a scoped instance of MonadState (as in, an instance that'll update part of the state) makes it impossible to keep an atomic update+get operation in the form of Ref's modify. |
Sounds good to me, let's add those consistency laws then and we should be good to go :) |
@LukaJCB I added these laws, and as I understand they should be internal. Do they make sense? |
The issue here is that atomic modify is not about adding laws, but relaxing them. set(a) >> get = set(a) >> a.pure but you cannot rely on this law in substitutions where concurrency is involved: (set(a) >> get, set(b).parMapN((a,_) => a) // is not the same as
(set(a) >> a.pure, set(b)).parMapN((a, _) => a) The latter always returns |
This one seems also incorrect to me, there could be a concurrent update in between |
It's true @SystemFw, I was going to mention it at some point but forgot... I added this |
I think that's the crux of the discussion: is MonadState an abstraction over sequential state like |
paging @oleg-py as meow-mtl's usecase is one of the reason this PR exists |
I'd say yes, and I'm all for relaxing the definition to just a few state actions that are atomic by themselves. |
How is the resulting thing different from |
Classy lenses. Can you create a |
@SystemFw could you take a look? Ping me on gitter if you think we need a longer discussion :) |
Unrelated, but with a |
I meant conceptually. The same code that is used in |
Conceptually it's the same thing as what meow-mtl does for MonadState in general. The only other thing that this adds beyond what a custom function creating a "scoped" Ref would be an abstraction over that and State.apply. |
Maybe we should consider having different abstractions for (potentially) concurrent and sequential state. The latter would have more laws, and would be able to get a default implementation of this method by using get + set. Something like |
Alright, here it goes: What we agree on:
I would also state that:
What I suggest:
Alternatively, we could stop after step 2 and only weaken the laws + add |
Im +1 for steps 1,2,3. I have an existing use case for I think Apologies for the slow reply (the @mention had my name slightly misspelled so it didnt fire) |
My apologies for the misspelling @benhutchison, it's not even the first time... I'm not entirely sure SequentialState implies immutable Ask - even in State, doing |
IMO what's important is that this law is satisfied, which an
|
@kubukoz can you comment on why this is closed? I still feel there is a real issue here, and discussion in this thread improved my thinking about State. |
@benhutchison the thread has been inactive for quite a while, I personally have no interest in revisiting this until I have another usecase, and finally - the whole library had a major refactor/rewrite so names like And I was just cleaning my old PRs :) |
The aspect of this thread I found thought-provoking & valuable was the idea that State might come in two flavors: a weaker concurrent state where the state is unstable/variable between writes to the state (eg a concurrently modified Ref), and a stronger traditional State where one can read back whatever was last set into the state store. I hadn't encountered that distinction before in other libraries. It feels "real" but I'm not sure if it's practically useful. It suggests there's a similar distinction in Reader, between reading from an unstable environment and reading from an immutable one. |
It's hard work keeping track of everything that moves on the plain I just noticed Arman's ConcurrentStateful |
It has been mentioned on Gitter that such a function would be useful, especially for things like Ref that provide an atomic modify operation that allows returning a value depending on the previous state. Here it is.
It probably needs some laws, so I'll think about it and report back when I come up with something reasonable (will check what it looks like in Haskell world too).