5 ms·
AE (algebraic effect) are very interesting! Great article, thank you. Reading through, I have some concerns about usability in larger projects, mainly because
by michalsustr 1y ago
AE (algebraic effect) are very interesting! Great article, thank you.
Reading through, I have some concerns about usability in larger projects, mainly because of "jumping around".
> Algebraic effects can also make designing cleaner APIs easier.
This is debatable. It adds a layer of indirection (which I concede is present in many real non-AE codebases).
My main concern is: When I put a breakpoint in code, how do I figure out where the object I work with was created?
With explicit passing, I can go up and down the stack trace, and can find it.
But with AE composition, it can be hard to find the instantiation source -- you have to jump around, leading to yo-yo problem [1].
I don't have personal experience with AE, but with python generators, which the article says they are the same (resp. AE can be used to implement generators). Working through large complex generator expressions was very tedious and error-prone in my experience.
> And we can use this to help clean up code that uses one or more context objects.
The functions involved still need to write `can Use Strings` in their signature. From practical point of view, I fail to see the difference between explicitly passing strings and adding the `can Use Strings` signature -- when you want add passing extra context to existing functions, you still need to go to all of them and add the appropriate plumbing.
---
As I understand it, AE on low level is implemented as a longjmp instruction with register handling (so you can resume).
Given this, it is likely inevitable that in a code base where you have lots of AE, composing in various ways, you can get to a severe yo-yo problem, and getting really lost in what is the code doing.
This is probably not so severe on a single-person project, but in larger teams where you don't have the codebase in your head, this can be huge efficiency problem.
Btw. if someone understands how AE deal with memory allocations for resuming, I'd be very interested in a good link for reading, thank you!
[1]: https://en.wikipedia.org/wiki/Yo-yo_problem https://en.wikipedia.org/wiki/Yo-yo_problem
- codethief 1y ago> From practical point of view, I fail to see the difference between explicitly passing strings and adding the `can Use Strings` signature -- when you want add passing extra context to existing functions, you still need to go to all of them and add the appropriate plumbing. Couldn't the plumbing be reduced significantly through type inference? I.e. the function that invokes an effect will need the signature, the callers higher up the chain won't. Also, even if you had to adapt all the signatures, at least you wouldn't have to adjust the call sites themselves to pass in the context every single time.
- jfecher 1y agoRight, compared to explicitly passing the parameter, with effects: - You wouldn't have to edit the body of the function to thread through the parameter. - The `can Use Strings` part can be inferred (and in Ante's case, it is my goal to have the compiler write in inferred types for you so that top-level definitions can be inferred if desired but still annotated when committed for code review). - Most notably, the `can Use Strings` can be included in a type alias. You could have an alias `MyEffects = can Use Strings, Throw FooError`, etc for the effects commonly used in your program. If your state type is used pervasively throughout, this could be a good option. When you have such an alias it also means you'd just be editing the alias rather than every function individually. Generally though, while I think the passing around of state through effects can be useful it isn't the most convincing use of effects. I mention it more for "here's another benefit they can have" rather than "here's this amazing reason you should definitely use them for"
- codethief 1y ago> Generally though, while I think the passing around of state through effects can be useful it isn't the most convincing use of effects. I actually find it quite convincing, even if it might not be the main use case. Nowadays in imperative languages there are countless popular frameworks that resort to using & manipulating global state behind the scenes because drilling context through the call stack by hand is painful. Unfortunately, this makes understanding code much more difficult and testing it even more so.
- jfecher 1y ago> As I understand it, AE on low level is implemented as a longjmp instruction with register handling (so you can resume). Not quite. setjmp/lonjmp as they exist in C at least can jump up the call stack but not back down. I mention this at the end of the article but each language implements algebraic effects differently, and efficiency has improved in recent years. Languages can also optimize the effect differently based on how the handler is defined: - Handlers which are tail-resumptive can implement the effect as a normal closure call. - Handlers which don't call resume can be implemented as an exception or just return an error value at every step until the function exits the handler. - Handlers which perform work after resume is called (e.g. `| my_effect x -> foo (); resume (); bar ()` can be implemented with e.g. segmented call stacks. - Handlers where resume is called multiple times need an equivalent of a delimited continuation. Another way to implement these generally is to transform the effects into monads. For any set of effects you can translate it into a monad transformer where each effect is its own monad, or the free monad can be used as well. The cost in this approach is often from boxing closures passed to the bind function. Koka has its own approach where it translates effects to capability passing then bubbles them up to the handler (returns an error value until it gets to the handler). With just a few restrictions you can even specialize effects & handlers out of the program completely. This is what Effekt does. There really are a lot of options here. I have some links at the end of the article in the foot notes on papers for Koka and Effekt that implement the approaches above if you're interested.