pub fn simple_func(fetch: fn(String) -> String) -> List(Int) {
let keys = ["a", " b"]
list.map(keys, fn(key) {
let key = string.uppercase(key)
let value = fetch(key)
string.length(value)
})
}
and manually convert it into a code that, instead of performing this computation, builds essentially an AST that could be interpreted to perform this computation. But the whole point of the research into async/await, algebraic effects, etc. is so that you, the programmer, don't have to because your original program is already an AST that could be interpreted to perform the computation!
Your programming language already has semicolons, "foreach", and "return", so why force the programmer to use a combination of "continuation.then()", "continuation.each()", and "continuation.return()" instead? That's very much building a new programming language on top of an existing one and then solving the original problem at hand — well, perhaps the original programming language should just be better at solving the problems you want to solve?
With the AI era I really think there is a renaissance in functional programming, look at effect-ts which just reached 17M weekly downloads and is recommended by Claude itself when starting a new TypeScript project.
Effect-ts is kind of a continuation DSL interpreter, an interresting concepts they brought in addition to the error channel is the "R" dependency channel so that you can be type guided for missing injected dependencies, very cool for testability.
As all these structures (effects, continuations, ...) are monadic, the best part is the thigh composability possibilities as basically you can jut chain them.
Very cool to live the resurrection of all these 50's mathematics concepts, that takes all their sense now at AI era
I'm enjoying the resurrection of all these concepts. I hear it explained as agents work best with feedback/constraints, my confusion is I believe people do as well so why were they not so popular before. Either way it's nice to see it happening and I'm very bullish on Gleam continuing to be a good choice.
First of all, nice post! I can tell that you put deliberate effort into using a concrete example, introducing a problem and then building up to how to solve it.
However, the continuation monad has limitations. In your example, it serves a similar purpose to an abstract monad "typeclass"; where you can write an abstract "task" function and run it in the Result effect, or the Promise effect, or any other effect. However, this "task" function can only use map/bind/return, and cannot perform any specific "effectful" operation, such as throwing an error or performing async IO. At the point in the code where it performs an operation, it has to pick a concrete type for the continuation result type `t`. So, a function that performs async IO would need to return `K(Promise(b), a)`, and a function that throws an error would need to return `K(Result(b, Nil), a)`. What would be really useful would be to have a function can perform an effectful operation (such as throwing an error) and still return something like `M(b)` for some abstract effect `M`. This is one of the main problems of "effect systems," and to my understanding, what algebraic effects are currently trying to solve.
Well, yeah. You can do this, you can take
and manually convert it into a code that, instead of performing this computation, builds essentially an AST that could be interpreted to perform this computation. But the whole point of the research into async/await, algebraic effects, etc. is so that you, the programmer, don't have to because your original program is already an AST that could be interpreted to perform the computation!Your programming language already has semicolons, "foreach", and "return", so why force the programmer to use a combination of "continuation.then()", "continuation.each()", and "continuation.return()" instead? That's very much building a new programming language on top of an existing one and then solving the original problem at hand — well, perhaps the original programming language should just be better at solving the problems you want to solve?
With the AI era I really think there is a renaissance in functional programming, look at effect-ts which just reached 17M weekly downloads and is recommended by Claude itself when starting a new TypeScript project.
Effect-ts is kind of a continuation DSL interpreter, an interresting concepts they brought in addition to the error channel is the "R" dependency channel so that you can be type guided for missing injected dependencies, very cool for testability.
As all these structures (effects, continuations, ...) are monadic, the best part is the thigh composability possibilities as basically you can jut chain them.
Very cool to live the resurrection of all these 50's mathematics concepts, that takes all their sense now at AI era
I'm enjoying the resurrection of all these concepts. I hear it explained as agents work best with feedback/constraints, my confusion is I believe people do as well so why were they not so popular before. Either way it's nice to see it happening and I'm very bullish on Gleam continuing to be a good choice.
Effect's use of generators is also nice. While looking a bit off, it allows writing imperative business logic.
First of all, nice post! I can tell that you put deliberate effort into using a concrete example, introducing a problem and then building up to how to solve it.
However, the continuation monad has limitations. In your example, it serves a similar purpose to an abstract monad "typeclass"; where you can write an abstract "task" function and run it in the Result effect, or the Promise effect, or any other effect. However, this "task" function can only use map/bind/return, and cannot perform any specific "effectful" operation, such as throwing an error or performing async IO. At the point in the code where it performs an operation, it has to pick a concrete type for the continuation result type `t`. So, a function that performs async IO would need to return `K(Promise(b), a)`, and a function that throws an error would need to return `K(Result(b, Nil), a)`. What would be really useful would be to have a function can perform an effectful operation (such as throwing an error) and still return something like `M(b)` for some abstract effect `M`. This is one of the main problems of "effect systems," and to my understanding, what algebraic effects are currently trying to solve.