
I think "scoped exceptions" is basically also the same thing as what https://github.com/tek/polysemy-resume#readme implements, so it might be of interest to you. On 5/25/25 19:32, Tom Ellis wrote:
On Wed, Dec 28, 2022 at 08:38:04PM +0000, Tom Ellis wrote:
I'd like to implement "scoped exceptions"[1], that is, a combinator of type
withScopedException :: ((forall a. e -> IO a) -> IO r) -> IO (Either e r) [...] Here's a hacky way of doing it, based on tagging each exception with a unique value, and then filtering when handling:
data MyException where MyException :: e -> Data.Unique.Unique -> MyException
instance Show MyException where show _ = "<MyException>"
instance Exception MyException
withScopedException :: ((forall a. e -> IO a) -> IO r) -> IO (Either e r) wiathScopedException f = do fresh <- Data.Unique.newUnique flip tryJust (f (\e -> throwIO (MyException e fresh))) $ \case MyException e tag -> -- unsafeCoerce is very unpleasant if tag == fresh then Just (unsafeCoerce e) else Nothing
This is the approach taken by the effectful library[2]. But is there a better way? Can I persuade GHC's RTS to work like this directly? I found a better way, or more accurately LSLeary suggested it to me, now implemented in Bluefin.Internal.Exception.Scoped:
https://hackage-content.haskell.org/package/bluefin-internal-0.1.0.0/docs/Bl...
The innovation is to have a `Key` type that supports:
newKey :: IO (Key a) eqKey :: forall a b. Key a -> Key b -> Maybe (a :~~: b)
This allows us to tag thrown values with a `Key` and unwrap them only when we have another copy of the same key, which allows us to obtain type equality. (`Key` is also available in Apfelmus's `vault` package.)
Tom _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.