@@ -17,6 +17,10 @@ module Effectful.Internal.Monad
17 , unsafeEff_
17 , unsafeEff_
18 , unsafeUnliftEff
18 , unsafeUnliftEff
@@ -45,6 +49,7 @@ import Control.Monad.Fix
45import Control.Monad.IO.Class
49import Control.Monad.IO.Class
46import Control.Monad.IO.Unlift
50import Control.Monad.IO.Unlift
47import Control.Monad.Trans.Control
51import Control.Monad.Trans.Control
48import GHC.Magic (oneShot)
53import GHC.Magic (oneShot)
49import System.IO.Unsafe (unsafeDupablePerformIO)
54import System.IO.Unsafe (unsafeDupablePerformIO)
@@ -172,6 +177,43 @@ instance MonadMask (Eff es) where
172 c <- unEff (release resource $ ExitCaseSuccess b) es
177 c <- unEff (release resource $ ExitCaseSuccess b) es
173 pure (b, c)
178 pure (b, c)
180+----------------------------------------
183+data Fail :: Effect where
184+ Fail :: Unique -> Fail m r
186+runFail :: Eff (Fail : es) a -> Eff es (Either String a)
187+runFail m = unsafeEff $ \es0 -> mask $ \release -> do
188+ -- A unique tag is picked so that different runFail handlers don't catch each
189+ -- other's exceptions.
191+ size0 <- sizeEnv es0
192+ es <- unsafeConsEnv (IdE (Fail tag)) noRelinker es0
193+ r <- tryFailIO tag (release $ unEff m es) `onException` unsafeTailEnv size0 es
194+ _ <- unsafeTailEnv size0 es
197+instance Fail :> es => MonadFail (Eff es) where
198+ fail msg = readerEffectM $ \(IdE (Fail tag)) -> unsafeEff_ $ do
199+ throwM $ FailEx tag msg
203+data FailEx = FailEx Unique String
204+instance Show FailEx where
205+ showsPrec p (FailEx _ msg)
206+ = ("Effectful.Internal.Monad.FailEx " ++)
208+instance Exception FailEx
210+tryFailIO :: Unique -> IO a -> IO (Either String a)
212+ (Right <$> m) `catch` \err@(FailEx etag msg) -> do
214+ then pure $ Left msg
175----------------------------------------
217----------------------------------------