lexi-lambda / eff

🚧 a work in progress effect system for Haskell 🚧
ISC License
124 stars 2 forks source link

How does `eff` implement delimited control? #1

Open re-xyr opened 2 years ago

re-xyr commented 2 years ago

I am reading eff's source code and I saw that in the control operation, it throws a captured frame up to the handler to deal with, instead of resuming it in place. To me (who probably does not have enough context), this seems like extra indirection. What is the motivation for this design?

lexi-lambda commented 2 years ago

There are several subtleties here:

These requirements inform the “calling convention” used by EVM when capturing and restoring the continuation. This is all intimately related to the following comment:

https://github.com/lexi-lambda/eff/blob/8c4df4bf54faf22456354be18095b14825be5e85/eff/src/Control/Effect/Internal.hs#L283-L286

I still need to write up the appropriate Note to explain the full subtleties, but I’ll try to give a brief, high-level explanation here:

Another way of putting this is that we’re effectively using RTS exceptions as a way to determine whether or not a use of prompt# returned normally or not without growing the captured continuation. This works because RTS exceptions are a first-class mechanism that allow a computation to signal a non-normal return. Yes, this is all outrageously subtle, but that is why it is so important that this stuff is abstracted away in a library, not exposed directly to the user: getting this stuff right is too hard to make it possible to accidentally get it wrong.

re-xyr commented 2 years ago

Thanks for the writeup! The point about tail calls is indeed very subtle and helps me understand why onReturn exists. I have some other (perhaps stupid) questions: