Exerosis
01/23/2025, 8:54 AMYoussef Shoaib [MOD]
01/23/2025, 10:24 AMsuspend
being a keyword isn't that big of a deal. It really just marks effectful functions, while non-suspend functions are pure and side-effecty ones.
throw
really isn't that big of an issue either, it's really just an implicit effect given to all functions. Also, if you just restrict yourself from using it and instead use something like Arrow's Raise
, then you get back effect safety.Youssef Shoaib [MOD]
01/23/2025, 10:48 AMYoussef Shoaib [MOD]
01/23/2025, 3:44 PMExerosis
01/28/2025, 7:17 AMYoussef Shoaib [MOD]
01/28/2025, 4:54 PMsuspend
is basically a built-in monad with direct-style monad comprehensions if you will. Delimited continuations is the technical term for this, and they're widely used to implement effects. A language that supports delimited continuations directly (like Kotlin) doesn't need HKTs or Monads or anything like that. Instead, "evidence" or "capability" passing is used through context parameters so that one can define an interface like:
fun interface Amb {
suspend fun flip(): Boolean
}
and an effectful function that uses `Amb`is just:
suspend fun Amb.drunkFlip(): String {
val caught = flip()
val heads = if (caught) flip() else error("too drunk")
return if (heads) "heads" else "tails"
}
You could also use context parameters instead of an extension receiver here
An implementation of Amb can be defined as:
private suspend fun <R> selectAll(block: suspend Amb.() -> R): List<Result<R>> = buildList {
handle {
val amb = Amb {
this@handle.use { resume ->
resume(true)
resume(false)
}
}
add(runCatching { block(amb) })
}
}
and running with that implementation produces [Success(heads), Success(tails), Failure(java.lang.IllegalStateException: too drunk)]
The effects are passed on implicitly because of context parameters and receivers. There is the issue of effects escaping, which I've talked about above, but in short it's currently a runtime exception, but it's doable to make a compiler plugin that reports errors when that happens (and doesn't modify any code at all, so it's just a linter really). It's easy enough to spot those errors usually, and so it's not a big problem (and other languages with effects like Ocaml for instance don't have it)Exerosis
01/31/2025, 3:28 AMcontext(Others...) fun <From, To> List<From>.map(
mapper: context(Others...) (From) -> (To)
) = ...
https://gitlab.com/ballysta/architecture/-/tree/4.0.2/src/main/kotlin/com/gitlab/ballysta/architecture?ref_type=tags
I've been sort of refining this concept of a "component engine" for a long time. When I learned about algb effects and their relationships to continuations and context I started wondering if this idea of "Toggled" can be represented as an "effect" and what the pros and cons of that would be.
I'm still too new to the whole thought process (and traditional solutions) to provide effective feedback. But the scala discord has a lot of cool people including one of the guys behind https://www.unison-lang.org/ which explained alg effects to me 🙂
I plan to fork your repo and play around a bit over the weekend though, I certainly want to play with multishot in kotlin that's extremely cool tech 🙂Youssef Shoaib [MOD]
01/31/2025, 3:36 AMRaise
, which can be adapted for this too, but it might have a lot of false negatives (since the whole point is to capture the HandlerPrompt
inside of an object
2. There is never a need for that really, unless we're dealing with complicated usages of functions-as-values and such. Basically, right now no escape analysis happens, and so the mapper
just has access to the contexts it already had. When such an escape checker is made, functions would have to explicitly say that they don't preserve the same context (although I have some ideas to do that automagically. For instance, the calls-in-place contract seems to specify exactly that, so the escape analyser can use that as a signal to consider that an escape. Again, the point ultimately is to build a resource escape checker). There is a paper about this from the effekt-lang people called something like "Effects as Capabilities", and another one called "From scope-based to type-based reasoning and back" which discuss this idea. Roman Elizarov, the previous language designer, said before that explicit effect polymorphism (that Others... thing you're talking about) isn't really a good fit for mainstream languages, and that paper expands on that by completely hiding away effect polymorphism, and instead letting you reason thru `context`s, until you need to e.g. store a lambda somewhere, then the lambda has an explicit type annotation as to what effects it needsExerosis
01/31/2025, 3:57 AMYoussef Shoaib [MOD]
01/31/2025, 7:01 AMYoussef Shoaib [MOD]
05/27/2025, 11:24 AM@RestrictsSuspension
to ensure effect safety, although it's a little annoying to use due to the type inference just giving up sometimes. I'm basically doing monadic regions, and so effectful operations have a type variable that refers to the region they need to operate in. Also note that there's unsoundness bugs with @RestricitsSuspension
that allows one to escape such safety, but usually it's hard to just "stumble" on that, and they should be fixed eventually regardless.