←back to thread

97 points appliku | 4 comments | | HN request time: 0.879s | source
Show context
vips7L ◴[] No.45159540[source]
Maybe I’m not getting it, but isn’t this just interfaces and implementations from the OO world? For example their movie one is:

    interface MovieApi {
        List<Movie> getPopularMovies();
    }
    
What are effects providing over this?
replies(5): >>45159701 #>>45159720 #>>45160356 #>>45162050 #>>45194243 #
abeppu ◴[] No.45159720[source]
I _think_ the distinction is that the interface tells you what MovieAPI _does_, but this system also tracks what are contextual requirements to do that thing. So when they write their version of the MovieAPI that calls out to an existing web api, they have to write `\ {Net, IO}` on the main method that uses them. When they write their test that uses a canned recommendation, they can just write `\ {IO}`, and they have a complicated pile of test logic and confirm just at a glance at the top-level signature that no network calls are made when the test runs.

So in java, you could write two distinct classes implementing the MovieApi interface as you defined it, one of which calls out to the web and one which doesn't, and nothing about the type indicates that difference. If you accidentally used the wrong class, your tests could make a network call and you might never notice, because you would not have tracked that effect.

For someone with a java background, it's really helpful to make the analogy to Checked Exceptions, which let us propagate information about what kind of handler must be required contextually.

replies(1): >>45160507 #
alethic ◴[] No.45160507[source]
The checked exceptions analogy is a good one. Thinking of effect handlers as resumable checked exceptions with some syntactic sugar is very accurate. For someone with a Haskell background, thinking about them as "dependency injection" is also helpful (and these notions are equivalent!) but for the Java heads out there, yeah, resumable checked exceptions provides a really good mental model for what effect handlers are doing with the call stack in the general case.
replies(1): >>45165429 #
tome ◴[] No.45165429[source]
What’s the difference between a resumable checked exception and a function call?
replies(1): >>45165741 #
1. saviorand ◴[] No.45165741[source]
Function call always returns, and to one single caller, whereas effects can choose not to "return" at all, resume multiple times, etc
replies(1): >>45165987 #
2. tome ◴[] No.45165987[source]
Right, though the former is just an exception. So what general effect systems provide above and beyond what we already have in most languages is "multiply-resumable" checked exceptions (also known as multi-shot continuations and often provided by "delimited continuations").

At the time I developed my Haskell effect system Bluefin there was a conventional wisdom that "you can't implement coroutines without delimited continuations". That's not true: you can implement coroutines simply as function calls, and that's what Bluefin does.

(The story is not quite as simple as that, because in order for coroutines to communicate you need to be able to pass control between threads with their own stack, but you still don't need multi-shot continuation.)

replies(1): >>45167883 #
3. saviorand ◴[] No.45167883[source]
Good point! You might be interested in reading this article on the topic: https://without.boats/blog/coroutines-and-effects/
replies(1): >>45178726 #
4. tome ◴[] No.45178726{3}[source]
Thanks, I did find that interesting. I would say Bluefin is another entry in the static/lexical row, whereas its cousin effectful is in the static/dynamic row (although this may be a slightly different interpretation of the terms than is used in the article).