←back to thread

97 points appliku | 1 comments | | HN request time: 0.237s | source
Show context
artemonster ◴[] No.45158295[source]
I really want effects to shine and thrive, but since this is a very academic topic, only academic people engage with the research and it comes with academic pedantism, perfectionist worldview, strange attraction to beautiful consistency, etc. This automatically places effect research FAR from any practicality and grounded realism. 2 points, as examples: 1. Ever tried adding a simple print statement for debugging purposes while coding in effectful lang? compiler: "NNNOOOOO!!!! THIS IS AN ERROR; I WILL NEVER COMPILE THIS NONSENSE YOU __MUST__ SPECIFY CONSOLE EFFECT WAAARGHH!11" 2. multi-resumable stacks. how many times you really want to implement custom backtracking for multi resumable computations? this is such an obscure nonsensical use case that is hard to nearly impossible to solve efficiently, but everyone wants to support it. supporting this adds enormous complexity and kills any potential for performance. WHYYYYYYYYY. and yet they focus on this as a holy grail feature but whever there is a showcase they use synthetic "choice" example, lol.
replies(5): >>45158326 #>>45158495 #>>45158777 #>>45159774 #>>45162539 #
1. pchiusano ◴[] No.45162539[source]
The Unison language supports algebraic effects and optimizes handlers that call their continuation at most once in tail position (we call these "affine"), so you can have the best of both worlds. Some links at the end if you're curious.

Here are a few places where "multi-resumable" stacks are still useful, even outside of nondeterminism:

* For instance, in a workflow engine a la Temporal, a `sleep` primitive might serialize and store the continuation in a distributed priority queue. The workarounds of not having access to the continuation are all not nearly as good.

* A pure interpreter of a structured concurrency ability is quite useful for testing, since it can test different interleavings of threads and produce tests that fail or pass deterministically. For Unison Cloud's distributed programming API, we have an (in-progress) chaos monkey interpreter that you can use for local testing of distributed systems.

* You can implement a simple debugger... as a library. It lets you set breakpoints and go forwards and backwards in time. Here's an example: https://share.unison-lang.org/@pchiusano/stepwise

Basically, any time you want to stash and do something interesting with the continuation, even if you only end up ultimately using it once, you still need the more general form of algebraic effects.

And then there are various nondeterminism effects that do call the continuation more than once. I'd say these are somewhat niche, but when you need them, you need them, and the code comes out much nicer. I especially like it for testing. You generally want tests to just be the logic, not a bunch of looping code or map/flatMap.

Some links:

* https://www.linkedin.com/posts/pchiusano_dan-doel-has-been-d... has some details on the optimization we do in Unison

* https://dolio.unison-services.cloud/s/blog/posts/optimizing-... is Dan's blog post on optimizing affine handlers

* https://www.linkedin.com/posts/pchiusano_kestrel-is-a-higher... is a typed query DSL that uses nondeterminism in an interesting way. For a declarative query DSL, it's nice to avoid explicit looping, similar to what SQL does.