mirror of
https://github.com/haskell-effectful/effectful.git
synced 2024-11-22 22:14:21 +03:00
Add the Fail effect
This commit is contained in:
parent
acaf81096f
commit
fc8a1962ff
@ -71,6 +71,7 @@ library
|
||||
Effectful.Class.State
|
||||
Effectful.Class.Writer
|
||||
Effectful.Error
|
||||
Effectful.Fail
|
||||
Effectful.Internal.Effect
|
||||
Effectful.Internal.Env
|
||||
Effectful.Internal.Monad
|
||||
|
@ -65,7 +65,7 @@ throwError
|
||||
=> e
|
||||
-> Eff es a
|
||||
throwError e = readerEffectM @(Error e) $ \(IdE (Error tag)) -> unsafeEff_ $ do
|
||||
throwIO $ WrapErr tag callStack e
|
||||
throwIO $ ErrorEx tag callStack e
|
||||
|
||||
catchError
|
||||
:: forall e es a. (Typeable e, Error e :> es)
|
||||
@ -88,19 +88,18 @@ tryError m = (Right <$> m) `catchError` \es e -> pure $ Left (es, e)
|
||||
----------------------------------------
|
||||
-- Helpers
|
||||
|
||||
data WrapErr e = WrapErr Unique CallStack e
|
||||
|
||||
instance Typeable e => Show (WrapErr e) where
|
||||
showsPrec p (WrapErr _ cs e)
|
||||
= showsPrec p "Effectful.Error.WrapErr ("
|
||||
data ErrorEx e = ErrorEx Unique CallStack e
|
||||
instance Typeable e => Show (ErrorEx e) where
|
||||
showsPrec p (ErrorEx _ cs e)
|
||||
= ("Effectful.Error.ErrorEx (" ++)
|
||||
. showsPrec p (typeOf e)
|
||||
. showsPrec p ") "
|
||||
. (") " ++)
|
||||
. showsPrec p cs
|
||||
instance Typeable e => Exception (WrapErr e)
|
||||
instance Typeable e => Exception (ErrorEx e)
|
||||
|
||||
catchErrorIO :: Typeable e => Unique -> IO a -> (CallStack -> e -> IO a) -> IO a
|
||||
catchErrorIO tag m handler = do
|
||||
m `catch` \err@(WrapErr etag e cs) -> do
|
||||
m `catch` \err@(ErrorEx etag e cs) -> do
|
||||
if tag == etag
|
||||
then handler e cs
|
||||
else throwIO err
|
||||
|
6
src/Effectful/Fail.hs
Normal file
6
src/Effectful/Fail.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Effectful.Fail
|
||||
( Fail
|
||||
, runFail
|
||||
) where
|
||||
|
||||
import Effectful.Internal.Monad
|
@ -17,6 +17,10 @@ module Effectful.Internal.Monad
|
||||
, unsafeEff_
|
||||
, unsafeUnliftEff
|
||||
|
||||
-- * Fail
|
||||
, Fail
|
||||
, runFail
|
||||
|
||||
-- * IO
|
||||
, IOE
|
||||
, runIOE
|
||||
@ -45,6 +49,7 @@ import Control.Monad.Fix
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.IO.Unlift
|
||||
import Control.Monad.Trans.Control
|
||||
import Data.Unique
|
||||
import GHC.Magic (oneShot)
|
||||
import System.IO.Unsafe (unsafeDupablePerformIO)
|
||||
|
||||
@ -172,6 +177,43 @@ instance MonadMask (Eff es) where
|
||||
c <- unEff (release resource $ ExitCaseSuccess b) es
|
||||
pure (b, c)
|
||||
|
||||
----------------------------------------
|
||||
-- Fail
|
||||
|
||||
data Fail :: Effect where
|
||||
Fail :: Unique -> Fail m r
|
||||
|
||||
runFail :: Eff (Fail : es) a -> Eff es (Either String a)
|
||||
runFail m = unsafeEff $ \es0 -> mask $ \release -> do
|
||||
-- A unique tag is picked so that different runFail handlers don't catch each
|
||||
-- other's exceptions.
|
||||
tag <- newUnique
|
||||
size0 <- sizeEnv es0
|
||||
es <- unsafeConsEnv (IdE (Fail tag)) noRelinker es0
|
||||
r <- tryFailIO tag (release $ unEff m es) `onException` unsafeTailEnv size0 es
|
||||
_ <- unsafeTailEnv size0 es
|
||||
pure r
|
||||
|
||||
instance Fail :> es => MonadFail (Eff es) where
|
||||
fail msg = readerEffectM $ \(IdE (Fail tag)) -> unsafeEff_ $ do
|
||||
throwM $ FailEx tag msg
|
||||
|
||||
--------------------
|
||||
|
||||
data FailEx = FailEx Unique String
|
||||
instance Show FailEx where
|
||||
showsPrec p (FailEx _ msg)
|
||||
= ("Effectful.Internal.Monad.FailEx " ++)
|
||||
. showsPrec p msg
|
||||
instance Exception FailEx
|
||||
|
||||
tryFailIO :: Unique -> IO a -> IO (Either String a)
|
||||
tryFailIO tag m =
|
||||
(Right <$> m) `catch` \err@(FailEx etag msg) -> do
|
||||
if tag == etag
|
||||
then pure $ Left msg
|
||||
else throwM err
|
||||
|
||||
----------------------------------------
|
||||
-- IO
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user