Skip to content
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 Final Effect #217

Merged
merged 5 commits into from
Aug 30, 2019
Merged

Conversation

KingoftheHomeless
Copy link
Collaborator

There are a few things I want to hash out with you before I declare this ready.

@@ -66,7 +67,7 @@ withLowerToIO action = do
res <- embed $ A.async $ do
a <- action (runViaForklift inchan)
(putMVar signal ())
putMVar signal ()
`finally` (putMVar signal ())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pointing this out so you won't miss it; this fixes the "exception" part of #205 .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3

@KingoftheHomeless
Copy link
Collaborator Author

Should I add nonDetToFinal from polysemy-zoo? I feel it's borderline.

@@ -1,5 +1,5 @@
name: polysemy
version: 1.1.0.0
version: 1.2.0.0
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version bump in order to update dependencies for polysemy-plugin-test.

@@ -1,5 +1,34 @@
# Changelog for polysemy


## 1.2.0.0 (TODO)
Copy link
Collaborator Author

@KingoftheHomeless KingoftheHomeless Aug 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marked the date as TODO here since I figure we might want to do more for this version before we publish it to Hackage.

@KingoftheHomeless
Copy link
Collaborator Author

Pretty much ready now. It's a bit silly; I figured it'd be a bit longer before we were ready to merge this, which is why I first imported the final rework to polysemy-zoo. Now it turns out perhaps that version won't even reach polysemy-zoo on Hackage.

@KingoftheHomeless
Copy link
Collaborator Author

I'm gonna stew on this for a day to make sure I'm satisfied with it before I merge it in.

@KingoftheHomeless
Copy link
Collaborator Author

KingoftheHomeless commented Aug 30, 2019

A question in my mind is if we shouldn't just have runM process both Embed and Final, like the old version of runFinal:

runM :: Monad m => Sem '[Embed m, Final m] a -> m a

It's backwards-compatible (except when people explicitly write out their effect stack instead of using Members), and it means users won't have to juggle between runM and runFinal . embedToFinal.

Plus, if we do this we can remove runFinal and embedToFinal.

I know we already discussed this when it came to runFinal, but this is a little different because it allows us to unify how you interpret Embed and Final.

@KingoftheHomeless
Copy link
Collaborator Author

Oh, I should ping you too about that. It's the only unresolved question I have about this, with the exception of potential performance issues. @isovector

@KingoftheHomeless
Copy link
Collaborator Author

KingoftheHomeless commented Aug 30, 2019

For the record: the performance issue I'm worried about is how loopbreaker interacts with Final; Final works by using the distribution function provided by a weaving, the one that is generated by the
hoist runInterpreter g and weave ... g that interpreters do. The problem is that I think loopbreaker will, instead of injecting runInterpreter into the weaving, inject the NOINLINED loop-breaker runInterpreter_b, which will mean that when the distribution function is used, it isn't optimized.

It that's indeed the case, errorToIOFinal would get hit hard, as it uses the distribution function over all actions in order to attempt the try at the end. lower- interpreters don't have this issue since the user-supplied function will use the proper interpreters, and not the loop-breakers.

A quick and dirty fix for that is to have loopbreaker recurse 2 or 3 times before inserting the loop-breaker.

@KingoftheHomeless
Copy link
Collaborator Author

KingoftheHomeless commented Aug 30, 2019

@TheMatten Does that sound right to you? (As in, is it plausible that's indeed what would happen?)

I tried building GHC 8.9 to confirm this, but as I'm on windows, using Hadrian turned out to resemble hell much closer than to my liking.

@isovector
Copy link
Member

I'd prefer to keep runM as it is today, at least until 8.10 lands and we can better judge performance without needing to use our brains.

@KingoftheHomeless
Copy link
Collaborator Author

KingoftheHomeless commented Aug 30, 2019

Oh, the performance question was separate from the question about runM; runM was entirely about user convenience.

Whatever the case, I have no strong opinions. I prefer changing runM, but I'm not against keeping it the way it is.

@isovector
Copy link
Member

I guess I'm still not sure what Final buys us that interpret/embed doesn't, except for continuations?

(go . wv)
ex
ins
Left g -> hoist go g
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found this neat optimisation made possible from the new injWeaving, which cleans up the code to boot!

@TheMatten
Copy link
Collaborator

@KingoftheHomeless having some simple example that we can bench and -ddump-simpl would be nice. But honestly, loopbreaker is going to be rewritten to instead do Core pass for better reliability (it just wasn't needed for now and I forgot about it 🙂) - this will probably change how it behaves.

@KingoftheHomeless
Copy link
Collaborator Author

KingoftheHomeless commented Aug 30, 2019

Final let's us not need lowering functions for interpreting higher-order effects in terms of the final monad! That's really the main point of it all.

Although I found it while working on getting continuations to work, Final is orthogonal to that.

@isovector
Copy link
Member

Ahh, right. Sorry, not sure why I can't seem to remember that. I'm definitely sympathetic to the idea, though why do we need the Embed in runM :: Monad m => Sem '[Embed m, Final m] a -> m a. Just for backwards compatibility?

@TheMatten
Copy link
Collaborator

TheMatten commented Aug 30, 2019

@isovector As I understand it, this would let us use runM for both Embed or Final

@KingoftheHomeless
Copy link
Collaborator Author

KingoftheHomeless commented Aug 30, 2019

Partly backwards compatibility, partly user convenience. Since Embed is more flexible to interpret than Final, we don't want to simply replace Embed with Final; in fact, we want interpreters to use Embed instead when they don't need the extra power. So this means that at the end, you'll end up with Embed m and/or Final m. runM can be used under any circumstance here; even if you haven't made use of Embed m, or haven't made use of Final m. So it's a nice one-interpreter-fits-all.

@isovector
Copy link
Member

That's a pretty good argument. I'm on board, but let's hold off for a 2.0 release.

@KingoftheHomeless
Copy link
Collaborator Author

Ok! That's reasonable to me.

I'll go ahead and merge this, then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants