Recently I’ve heard Algebraic Effects a lot. After some investigation,
I’m very interested in implementing it in Pivot Lang. Algebraic Effects
is known for its ability to implement async/await, generators, try/catch
etc. in ease. As I’ve already implemented generators in Pivot Lang,
I immediately become curious about if I can use generators to implement
algebraic effects? If so, I can implement it in Pivot Lang with
minimal effort.
What is Algebraic Effects?
Well, basically, Algebraic Effects is a way to separate the side effects
from the computation. It’s a well-known concept in functional programming.
If you’re not familiar with it, I would recommend you to read this
article.
How to Implement Algebraic Effects with Generators?
Below is a simple example of my experiments, using Pivot Lang’s generator:
var effect1 = 1;
var effect2 = 2;
gen fn generator1() Iterator<i64> {
executeGenerator(generator2());
yield return effect1;
}
gen fn generator2() Iterator<i64> {
yield return effect2;
}
fn eff1handler(resolve: ||=>void) void {
println!("effect 1");
resolve();
return;
}
fn eff2handler(resolve: ||=>void) void {
println!("effect 2");
resolve();
return;
}
fn executeGenerator(g:Iterator<i64>) void {
let eff = g.next();
let resolve = || => {
executeGenerator(g);
return;
};
match eff {
i64(1) => {
eff1handler(resolve);
}
i64(2) => {
eff2handler(resolve);
}
_ => {
}
}
return;
}
fn main() void {
executeGenerator(generator1());
return;
}
In this example, I have two effects effect1 and effect2. I have two
generators generator1 and generator2. generator1 will yield effect1
and generator2 will yield effect2. I have two handlers eff1handler
and eff2handler to handle the effects. executeGenerator will execute
the generator and call the corresponding handler.
If we need to add effect to Pivot Lang, every function that may use
the effect should be a generator. This is, of course, a performance
overhead. It’s just like making every function async in JavaScript.