[prev in list] [next in list] [prev in thread] [next in thread] 

List:       haskell-cafe
Subject:    Re: [Haskell-cafe] Best way to implement "scoped exceptions"?
From:       Tom Ellis <tom-lists-haskell-cafe-2017 () jaguarpaw ! co ! uk>
Date:       2023-06-16 11:11:27
Message-ID: ZIxDX0nIDTswev8u () cloudinit-builder
[Download RAW message or body]

On Thu, Dec 29, 2022 at 03:41:22PM +0000, Tom Ellis wrote:
> On Thu, Dec 29, 2022 at 01:31:47PM +0000, Li-yao Xia wrote:
> > The recently implemented Delimited Continuation Primops proposal[1] features
> > tagged prompts. That seems like just what you are looking for.
> > 
> > [1]: https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0313-delimited-continuation-primops.rst
> > 
> 
> Very interesting, thanks!  My initial attempt at implementing scoped
> exceptions using the delimited continuation primops was bad:
> 
> withScopedExceptionBad ::
> ((e -> IO (Either e r)) -> IO r) -> IO (Either e r)
> withScopedExceptionBad body = do
> promptTag <- newPromptTag
> prompt promptTag $ do
> l <- control0 promptTag $ \myThrow -> do
> r <- body (myThrow . pure)
> pure (Right r)
> pure (Left l)
> 
> It was very head-scratching trying to work out how it should be
> implemented.  Then with the help of a gist by sebfisch[1] I managed
> it:
> 
> withScopedException ::
> ((forall a. e -> IO a) -> IO r) -> IO (Either e r)
> withScopedException body = do
> promptTag <- newPromptTag
> prompt promptTag $ do
> r <- body (\e -> control0 promptTag (\_ -> pure (Left e)))
> pure (Right r)
> 
> Surprisingly to me, for scoped exceptions, the handler passed to
> control0 should *ignore* its argument.  That's because its argument
> allows it to escape from the call to control0, but we want to escape
> from the call to prompt.  This is very powerful and mind-bending stuff
> and allows me to do exactly what I wanted.

Inspired by Alexis King's excellent talk recently at ZuriHac I
reimplemented this in a more general way.

    https://www.youtube.com/watch?v=aaApZhfisbs

    ZuriHac 2023 — Alexis King — Delimited Continuations, Demystified 

"withScopedEffect" allows to use any handler you like for the "effect".

    withScopedEffect ::
      (a -> (IO b -> IO r) -> IO r) -> ((a -> IO b) -> IO r) -> IO r
      withScopedEffect handler body = do
        promptTag <- newPromptTag
        prompt
          promptTag
          (body (\e -> control0 promptTag (\k -> handler e (prompt promptTag . k))))
    
    withScopedException :: ((e -> IO Void) -> IO r) -> IO (Either e r)
    withScopedException body =
      withScopedEffect (\e _ -> pure (Left e)) (fmap Right . body)
    
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.


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic