> no indication that foo or bar can fail ... how do you find the code that will run when they do fail
If that's what you're looking for you might want to try my Haskell effects library Bluefin (it's not an "algebraic" effects library, though). The equivalent code would be
myFunction :: e :> es -> Exception String e -> Eff es r
myFunction ex = do
x <- LibraryA.foo ex
y <- LibraryB.foo ex
z <- LibraryC.foo
...
This answers the first part of your question: the presence of `ex` argument (an `Exception String` handle) shows that a String-value exception can be thrown wherever they are used. For example, we know that `LibraryC.foo` does not throw that exception.
It also answers the second part of your question: the code that runs on failure is exactly the code that created the `Exception String` handle. Any exception arising from that handle is always caught where the handle was created, and nowhere else. For example, it could be here:
try $ \ex -> do
v <- myFunction ex
...
`try` catches the exception and turns into into the `Left` branch of a Haskell `Either` type. Or it could be here:
myFunction :: e :> es -> Exception String e -> Eff es r
myFunction ex = do
catch
(\ex2 -> do
x <- LibraryA.foo ex
y <- LibraryB.foo ex2
z <- LibraryC.foo
...)
(\errMsg -> logErr errMsg)
So the exception thrown by `LibraryB.foo` is always handled with the `logErr` (and nowhere else), and the exception thrown by `LibraryA.foo` is always handled by the exception handler higher up which created `ex` (and nowhere else).
I'm a bit confused at the distinction of "algebraic" vs "non-algebraic" effects. Think you can give a brief example of what you mean?
Also, I know you've taken a slightly different direction with Bluefin than other Haskell effects libraries (effects as values vs types). Is this related to the distinction above?
> I'm a bit confused at the distinction of "algebraic" vs "non-algebraic" effects. Think you can give a brief example of what you mean?
I don't fully understand what exactly "algebraic" effects are, but I think they're something like the entirety of effects that can safely be implemented with delimited continuations. Since Bluefin doesn't use delimited continuations (just the traditional standard GHC RTS effects: exceptions, state, IO, threads) it's not "algebraic".
> Also, I know you've taken a slightly different direction with Bluefin than other Haskell effects libraries (effects as values vs types). Is this related to the distinction above?
If that's what you're looking for you might want to try my Haskell effects library Bluefin (it's not an "algebraic" effects library, though). The equivalent code would be
This answers the first part of your question: the presence of `ex` argument (an `Exception String` handle) shows that a String-value exception can be thrown wherever they are used. For example, we know that `LibraryC.foo` does not throw that exception.It also answers the second part of your question: the code that runs on failure is exactly the code that created the `Exception String` handle. Any exception arising from that handle is always caught where the handle was created, and nowhere else. For example, it could be here:
`try` catches the exception and turns into into the `Left` branch of a Haskell `Either` type. Or it could be here: So the exception thrown by `LibraryB.foo` is always handled with the `logErr` (and nowhere else), and the exception thrown by `LibraryA.foo` is always handled by the exception handler higher up which created `ex` (and nowhere else).Let me know what you think!