effekt-lang / effekt-lang/effekt
Recursive Handlers
- Dominant language
- Scala
- Stars
- 469
- Forks
- 41
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 23
Description
Effekt has recursive objects (i.e. object methods can call themselves recursively), but it doesn't have recursive handlers. Obviously, a handler method shouldn't be able to directly call itself or its fellow handlers, since its prompt is not present (under shift0 semantics). What I mean is that, bidirectional/higher-order resume should allow you to perform this handler's effects.
This relates to #1176 since (I believe) the type of bidirectional `resume` is incorrect, so it's the perfect time to introduce this.
Do note that this changes semantics slightly; some code might've relied on `do sayHello` being handled by an outer handler.
Example:
```effekt
interface Dummy {}
interface Greet {
def sayHello(): Unit
def sayGoodbye(): Unit / Dummy
}
def helloWorld(): Unit / {} = try {
do sayGoodbye()
} with Greet {
def sayGoodbye = {
resume {
do sayHello() // Effect Greet is not allowed in this context.
}
}
def sayHello() = { println("Hello!"); resume(()) }
} with Dummy {}
```
In fact, it'd be perfectly reasonable to allow calling "sister" handlers that are on the same `try` as well:
```effekt
interface Dummy {}
interface Dummy2 {
def dummy(): Unit
}
interface Greet {
def sayHello(): Unit
def sayGoodbye(): Unit / Dummy
}
def helloWorld(): Unit / {} = try {
do sayGoodbye()
} with Greet {
def sayGoodbye = {
resume {
do dummy() // Effect Dummy2 is not allowed in this context.
}
}
def sayHello() = { println("Hello!"); resume(()) }
} with Dummy2 { def dummy() = resume(()) }
with Dummy { }
```
This is *guaranteed* to be safe because, in effekt, handlers are deep, and we're 100% sure that we're pushing the prompt for the `try` when we call `resume`, hence, in the local context of the effect call, our handler and its sister handlers are guaranteed to be valid (after all, that's how our handler got called in the first place). Do note that a similar argument is made to justify being able to use outside handlers in local resumptions; it's just that using the same handler (or its sisters) has been forgotten about.
One final note to add: Looking at the first example, I had to add `Dummy` to force having bidirectional effects so that I can get the special `resume`. That makes perfect sense currently, since the special local resume is useless without bidirectional/higher-order effects (because of lexical handlers). However, if this gets implemented, then there are legitimate cases for someone to use local resume purely for the purpose of calling their handler (or a sister handler) recursively. That should probably be supported too (although there are likely workarounds by creating an object since object method bodies are local)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.