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
State is discarded inside bracket
dealloc actions
#84
Comments
bracket
dealloc actionsbracket
dealloc actions
Both of these seem wrong to me too; I'm sure that this used to work. Let me dive in and write some tests. |
Nevermind, this is "expected behavior," for some definition of expected. The type of base's There's a workaround, which is to use |
To be more explicit about why this doesn't work, polysemy instantiates base's bracket at
which is why the |
In #73 we've been chatting about this problem more generally. I think that in this particular case, the bug might just be a quirk of the Maybe it's a cop-out, but also maybe this is more of a documentation bug than anything else? |
Another
This is a cop-out to me. This is a very real problem, and is half the reason that |
On second thought, even if we use get |
Discounting the above, |
It's worth slowing down, what is the behavior that we want? We can hardly strive to have correct behavior in runStateT
(bracketStateT
(pure ())
(const (sendM . print =<< get @Integer))
(const (put 2)))
0 Where |
I'd like
and
for the two examples, respectively. In other news, the applicative idea above won't work, since we don't get the |
Responded to this discussion over to #73 in a better thought-out manner. I'm going to suggest we continue the chat there, since it makes sense to leave this ticket as a place to talk about the particular bug in question. |
"Effect Handlers in Scope" points out the following:
It seems to me that this is the more fundamental problem here in #84. We don't have a place to |
Sorry for opening this issue and disappearing. Something like |
My main problem with MonadBaseControl is that it is too easy to accidentally discard state.
One needs to think carefully about the runtime behaviour of this implementation in order to realize that With polysemy, however, the implementation does look suspicious:
The So, in my eyes, that's the advantage of polysemy over MonadBaseControl: when implementing an effect which discards state, you'll know that you are discarding the state, so you are more likely to mention the fact that the effects are discarded in your documentation. But for the users, the end result is the same: both implementations discard the state, that fact is not obvious from the types, and so we keep getting paper cuts while using those libraries. At least MonadBaseControl documents the fact that the effects get discarded! |
@ocharles and I have a potential solution to this problem, which is to track the state functor |
By the way, that's also the approach taken by MonadBaseControl: restricting some lifted functions to the safe case in which |
Surprisingly, this is not the case:
It turns out there are two different ways in which
The fact that (1) is happening is just as hard to see in the polysemy implementation as in the MonadBaseControl implementation. Polysemy makes (2) obvious in some circumstances, by forcing the implementation to call The
Then, in
That
the Perhaps it would be worth making the
I realize, however, that this goes in the opposite of the direction you want to explore, in which the |
How would you write |
In the same way
The caller is supposed to see all of the effects, so we'd somehow need to keep track of the highest number (in this case 3) and ask the interpreter to return that:
All right, now the happy case in which no effects get dropped looks like this:
And the case in which some of the effects are dropped looks like this:
Our piece of machinery is As requested, here's how we can write
It should now be obvious from the I think an implementation based on |
This would be fixed by #126 |
This PR adds `runResourceBase` (which is a crap name, but naming things is hard), which interprets `Resource` without the ugly `Sem r ~> IO` parameter. It's a nice solution to #84!
@gelisam I've only skimmed your comment, but it looks very similar to what's going on in Syntax and Semantics for Operations with Scopes - is it the same thing? |
@ocharles No, I don’t see any link between that paper and any of my comments. I am guessing that the similarity you noticed is that we both use type-level natural numbers in relation to an interpreter, but we use them in completely different ways. For the benefit of others who are following this thread, here is a summary of the paper. I don't think the formalism used in the paper is able to represent the type of The reason algebraicity matters is that we need a way to represent programs containing To solve this problem, the key idea is that That's neat, but polysemy's Those type-level naturals come from the fact that the open and close operations and delimiters can nest arbitrarily deep, and so the naturals track how deeply-nested the code is. More precisely, an interpreter may choose to interpret blocks of code at different depths to different types, which it may specify by defining a type family As you can see, the paper uses type-level naturals in a completely different way than I am. They are requiring the interpreter to choose a type family and to implement functions on that type family, whereas I am proposing to provide the interpreter with an opaque type family and to provide the interpreter with a few functions on that type family. Furthermore, all the inputs of their open operation have the same type-level number, namely one more than the open operation itself, whereas I am proposing that they should have different numbers in order to enforce that the output of one is fed as the input of the next. |
Thanks @gelisam - that was exactly my question. |
Both these results seem wrong to me:
It seems like it ought to be possible to fix this by using a custom version of
bracket
insiderunResource
that threads the state through appropriately, but if that’s necessary, then I suppose I’m a little confused about what makes the approachpolysemy
takes any better thanMonadBaseControl
with respect to dropping state.The text was updated successfully, but these errors were encountered: