diff --git a/effectful-core/CHANGELOG.md b/effectful-core/CHANGELOG.md index 9aa1807..ecfbc68 100644 --- a/effectful-core/CHANGELOG.md +++ b/effectful-core/CHANGELOG.md @@ -11,6 +11,7 @@ * Fix a bug in `stateM` and `modifyM` of thread local `State` effect that might've caused dropped state updates ([#237](https://github.com/haskell-effectful/effectful/issues/237)). +* Add `HasCallStack` constraints for easier debugging. * **Breaking changes**: - `localSeqLend`, `localLend`, `localSeqBorrow` and `localBorrow` now take a list of effects instead of a single one. diff --git a/effectful-core/src/Effectful/Dispatch/Dynamic.hs b/effectful-core/src/Effectful/Dispatch/Dynamic.hs index 06b8414..d9e383e 100644 --- a/effectful-core/src/Effectful/Dispatch/Dynamic.hs +++ b/effectful-core/src/Effectful/Dispatch/Dynamic.hs @@ -428,7 +428,7 @@ import Effectful.Internal.Utils -- /Note:/ 'interpret' can be turned into a 'reinterpret' with the use of -- 'inject'. interpret - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => EffectHandler e es -- ^ The effect handler. -> Eff (e : es) a @@ -442,7 +442,7 @@ interpret handler m = unsafeEff $ \es -> do -- -- @since 2.4.0.0 interpretWith - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => Eff (e : es) a -> EffectHandler e es -- ^ The effect handler. @@ -453,7 +453,7 @@ interpretWith m handler = interpret handler m -- -- @'interpret' ≡ 'reinterpret' 'id'@ reinterpret - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> EffectHandler e handlerEs @@ -470,7 +470,7 @@ reinterpret runHandlerEs handler m = unsafeEff $ \es -> do -- -- @since 2.4.0.0 reinterpretWith - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> Eff (e : es) a @@ -508,7 +508,7 @@ reinterpretWith runHandlerEs m handler = reinterpret runHandlerEs handler m -- op -- interpose - :: forall e es a. (DispatchOf e ~ Dynamic, e :> es) + :: forall e es a. (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => EffectHandler e es -- ^ The effect handler. -> Eff es a @@ -537,7 +537,7 @@ interpose handler m = unsafeEff $ \es -> do -- -- @since 2.4.0.0 interposeWith - :: (DispatchOf e ~ Dynamic, e :> es) + :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => Eff es a -> EffectHandler e es -- ^ The effect handler. @@ -549,7 +549,7 @@ interposeWith m handler = interpose handler m -- -- @'interpose' ≡ 'impose' 'id'@ impose - :: forall e es handlerEs a b. (DispatchOf e ~ Dynamic, e :> es) + :: forall e es handlerEs a b. (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> EffectHandler e handlerEs @@ -582,7 +582,7 @@ impose runHandlerEs handler m = unsafeEff $ \es -> do -- -- @since 2.4.0.0 imposeWith - :: (DispatchOf e ~ Dynamic, e :> es) + :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> Eff es a @@ -607,7 +607,7 @@ type EffectHandler_ (e :: Effect) (es :: [Effect]) -- -- @since 2.4.0.0 interpret_ - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => EffectHandler_ e es -- ^ The effect handler. -> Eff (e : es) a @@ -618,7 +618,7 @@ interpret_ handler = interpret (const handler) -- -- @since 2.4.0.0 interpretWith_ - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => Eff (e : es) a -> EffectHandler_ e es -- ^ The effect handler. @@ -629,7 +629,7 @@ interpretWith_ m handler = interpretWith m (const handler) -- -- @since 2.4.0.0 reinterpret_ - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> EffectHandler_ e handlerEs @@ -642,7 +642,7 @@ reinterpret_ runHandlerEs handler = reinterpret runHandlerEs (const handler) -- -- @since 2.4.0.0 reinterpretWith_ - :: DispatchOf e ~ Dynamic + :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> Eff (e : es) a @@ -655,7 +655,7 @@ reinterpretWith_ runHandlerEs m handler = reinterpretWith runHandlerEs m (const -- -- @since 2.4.0.0 interpose_ - :: (DispatchOf e ~ Dynamic, e :> es) + :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => EffectHandler_ e es -- ^ The effect handler. -> Eff es a @@ -666,7 +666,7 @@ interpose_ handler = interpose (const handler) -- -- @since 2.4.0.0 interposeWith_ - :: (DispatchOf e ~ Dynamic, e :> es) + :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => Eff es a -> EffectHandler_ e es -- ^ The effect handler. @@ -677,7 +677,7 @@ interposeWith_ m handler = interposeWith m (const handler) -- -- @since 2.4.0.0 impose_ - :: (DispatchOf e ~ Dynamic, e :> es) + :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> EffectHandler_ e handlerEs @@ -690,7 +690,7 @@ impose_ runHandlerEs handler = impose runHandlerEs (const handler) -- -- @since 2.4.0.0 imposeWith_ - :: (DispatchOf e ~ Dynamic, e :> es) + :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -- ^ Introduction of effects encapsulated within the handler. -> Eff es a @@ -960,7 +960,7 @@ localLiftUnliftIO (LocalEnv les) strategy k = case strategy of -- @since 2.4.0.0 localSeqLend :: forall lentEs es handlerEs localEs a - . (KnownSubset lentEs es, SharedSuffix es handlerEs) + . (HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a) -- ^ Continuation with the lent handler in scope. @@ -977,7 +977,7 @@ localSeqLend (LocalEnv les) k = unsafeEff $ \es -> do -- @since 2.4.0.0 localLend :: forall lentEs es handlerEs localEs a - . (KnownSubset lentEs es, SharedSuffix es handlerEs) + . (HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a) @@ -997,7 +997,7 @@ localLend (LocalEnv les) strategy k = case strategy of -- @since 2.4.0.0 localSeqBorrow :: forall borrowedEs es handlerEs localEs a - . (KnownSubset borrowedEs localEs, SharedSuffix es handlerEs) + . (HasCallStack, KnownSubset borrowedEs localEs, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a) -- ^ Continuation with the borrowed handler in scope. @@ -1015,7 +1015,7 @@ localSeqBorrow (LocalEnv les) k = unsafeEff $ \es -> do -- @since 2.4.0.0 localBorrow :: forall borrowedEs es handlerEs localEs a - . (KnownSubset borrowedEs localEs, SharedSuffix es handlerEs) + . (HasCallStack, KnownSubset borrowedEs localEs, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a) diff --git a/effectful-core/src/Effectful/Error/Dynamic.hs b/effectful-core/src/Effectful/Error/Dynamic.hs index 0e17e41..1f69cd6 100644 --- a/effectful-core/src/Effectful/Error/Dynamic.hs +++ b/effectful-core/src/Effectful/Error/Dynamic.hs @@ -44,7 +44,8 @@ type instance DispatchOf (Error e) = Dynamic -- | Handle errors of type @e@ (via "Effectful.Error.Static"). runError - :: Eff (Error e : es) a + :: HasCallStack + => Eff (Error e : es) a -> Eff es (Either (E.CallStack, e) a) runError = reinterpret E.runError $ \env -> \case ThrowErrorWith display e -> E.throwErrorWith display e @@ -56,7 +57,8 @@ runError = reinterpret E.runError $ \env -> \case -- -- @since 2.3.0.0 runErrorWith - :: (E.CallStack -> e -> Eff es a) + :: HasCallStack + => (E.CallStack -> e -> Eff es a) -- ^ The error handler. -> Eff (Error e : es) a -> Eff es a @@ -69,14 +71,16 @@ runErrorWith handler m = runError m >>= \case -- -- @since 2.3.0.0 runErrorNoCallStack - :: Eff (Error e : es) a + :: HasCallStack + => Eff (Error e : es) a -> Eff es (Either e a) runErrorNoCallStack = fmap (either (Left . snd) Right) . runError -- | Handle errors of type @e@ (via "Effectful.Error.Static") with a specific -- error handler. In case of an error discard the 'CallStack'. runErrorNoCallStackWith - :: (e -> Eff es a) + :: HasCallStack + => (e -> Eff es a) -- ^ The error handler. -> Eff (Error e : es) a -> Eff es a diff --git a/effectful-core/src/Effectful/Error/Static.hs b/effectful-core/src/Effectful/Error/Static.hs index efe5402..6177ea7 100644 --- a/effectful-core/src/Effectful/Error/Static.hs +++ b/effectful-core/src/Effectful/Error/Static.hs @@ -118,7 +118,8 @@ newtype instance StaticRep (Error e) = Error ErrorId -- | Handle errors of type @e@. runError :: forall e es a - . Eff (Error e : es) a + . HasCallStack + => Eff (Error e : es) a -> Eff es (Either (CallStack, e) a) runError m = unsafeEff $ \es0 -> mask $ \unmask -> do eid <- newErrorId @@ -136,7 +137,8 @@ runError m = unsafeEff $ \es0 -> mask $ \unmask -> do -- -- @since 2.3.0.0 runErrorWith - :: (CallStack -> e -> Eff es a) + :: HasCallStack + => (CallStack -> e -> Eff es a) -- ^ The error handler. -> Eff (Error e : es) a -> Eff es a @@ -149,14 +151,16 @@ runErrorWith handler m = runError m >>= \case -- @since 2.3.0.0 runErrorNoCallStack :: forall e es a - . Eff (Error e : es) a + . HasCallStack + => Eff (Error e : es) a -> Eff es (Either e a) runErrorNoCallStack = fmap (either (Left . snd) Right) . runError -- | Handle errors of type @e@ with a specific error handler. In case of an -- error discard the 'CallStack'. runErrorNoCallStackWith - :: (e -> Eff es a) + :: HasCallStack + => (e -> Eff es a) -- ^ The error handler. -> Eff (Error e : es) a -> Eff es a @@ -199,7 +203,7 @@ throwError_ = withFrozenCallStack throwErrorWith (const "") -- | Handle an error of type @e@. catchError - :: forall e es a. Error e :> es + :: forall e es a. (HasCallStack, Error e :> es) => Eff es a -- ^ The inner computation. -> (CallStack -> e -> Eff es a) @@ -213,7 +217,7 @@ catchError m handler = unsafeEff $ \es -> do -- | The same as @'flip' 'catchError'@, which is useful in situations where the -- code for the handler is shorter. handleError - :: forall e es a. Error e :> es + :: forall e es a. (HasCallStack, Error e :> es) => (CallStack -> e -> Eff es a) -- ^ A handler for errors in the inner computation. -> Eff es a @@ -224,7 +228,7 @@ handleError = flip catchError -- | Similar to 'catchError', but returns an 'Either' result which is a 'Right' -- if no error was thrown and a 'Left' otherwise. tryError - :: forall e es a. Error e :> es + :: forall e es a. (HasCallStack, Error e :> es) => Eff es a -- ^ The inner computation. -> Eff es (Either (CallStack, e) a) diff --git a/effectful-core/src/Effectful/Fail.hs b/effectful-core/src/Effectful/Fail.hs index 1f96857..3038b16 100644 --- a/effectful-core/src/Effectful/Fail.hs +++ b/effectful-core/src/Effectful/Fail.hs @@ -14,11 +14,11 @@ import Effectful.Error.Static import Effectful.Internal.Monad (Fail(..)) -- | Run the 'Fail' effect via 'Error'. -runFail :: Eff (Fail : es) a -> Eff es (Either String a) +runFail :: HasCallStack => Eff (Fail : es) a -> Eff es (Either String a) runFail = reinterpret_ runErrorNoCallStack $ \case Fail msg -> throwError msg -- | Run the 'Fail' effect via the 'MonadFail' instance for 'IO'. -runFailIO :: IOE :> es => Eff (Fail : es) a -> Eff es a +runFailIO :: (HasCallStack, IOE :> es) => Eff (Fail : es) a -> Eff es a runFailIO = interpret_ $ \case Fail msg -> liftIO $ fail msg diff --git a/effectful-core/src/Effectful/Internal/Env.hs b/effectful-core/src/Effectful/Internal/Env.hs index 631b4fe..f4ca498 100644 --- a/effectful-core/src/Effectful/Internal/Env.hs +++ b/effectful-core/src/Effectful/Internal/Env.hs @@ -126,7 +126,7 @@ type family EffectRep (d :: Dispatch) :: Effect -> Type -- Operations -- | Create an empty environment. -emptyEnv :: IO (Env '[]) +emptyEnv :: HasCallStack => IO (Env '[]) emptyEnv = Env 0 <$> (unsafeFreezePrimArray =<< newPrimArray 0) <*> (newIORef' =<< emptyStorage) @@ -196,7 +196,8 @@ tailEnv (Env offset refs storage) = do -- | Extend the environment with a new data type. consEnv - :: EffectRep (DispatchOf e) e + :: HasCallStack + => EffectRep (DispatchOf e) e -- ^ The representation of the effect. -> Relinker (EffectRep (DispatchOf e)) e -> Env es @@ -216,7 +217,7 @@ consEnv e f (Env offset refs0 storage) = do -- -- /Note:/ after calling this function @e@ from the input environment is no -- longer usable. -unconsEnv :: Env (e : es) -> IO () +unconsEnv :: HasCallStack => Env (e : es) -> IO () unconsEnv (Env _ refs storage) = do deleteEffect storage (indexPrimArray refs 0) {-# NOINLINE unconsEnv #-} @@ -228,7 +229,7 @@ unconsEnv (Env _ refs storage) = do -- /Note:/ unlike in 'putEnv' the value in not changed in place, so only the new -- environment will see it. replaceEnv - :: forall e es. e :> es + :: forall e es. (HasCallStack, e :> es) => EffectRep (DispatchOf e) e -- ^ The representation of the effect. -> Relinker (EffectRep (DispatchOf e)) e @@ -250,7 +251,7 @@ replaceEnv e f (Env offset refs0 storage) = do -- -- /Note:/ after calling this function the input environment is no longer -- usable. -unreplaceEnv :: forall e es. e :> es => Env es -> IO () +unreplaceEnv :: forall e es. (HasCallStack, e :> es) => Env es -> IO () unreplaceEnv (Env offset refs storage) = do deleteEffect storage $ indexPrimArray refs (offset + 2 * reifyIndex @e @es) {-# NOINLINE unreplaceEnv #-} @@ -301,7 +302,7 @@ injectEnv (Env offset refs0 storage) = do -- | Extract a specific data type from the environment. getEnv - :: forall e es. e :> es + :: forall e es. (HasCallStack, e :> es) => Env es -- ^ The environment. -> IO (EffectRep (DispatchOf e) e) getEnv env = do @@ -310,7 +311,7 @@ getEnv env = do -- | Replace the data type in the environment with a new value (in place). putEnv - :: forall e es. e :> es + :: forall e es. (HasCallStack, e :> es) => Env es -- ^ The environment. -> EffectRep (DispatchOf e) e -> IO () @@ -320,7 +321,7 @@ putEnv env e = do -- | Modify the data type in the environment and return a value (in place). stateEnv - :: forall e es a. e :> es + :: forall e es a. (HasCallStack, e :> es) => Env es -- ^ The environment. -> (EffectRep (DispatchOf e) e -> (a, EffectRep (DispatchOf e) e)) -> IO a @@ -332,7 +333,7 @@ stateEnv env f = do -- | Modify the data type in the environment (in place). modifyEnv - :: forall e es. e :> es + :: forall e es. (HasCallStack, e :> es) => Env es -- ^ The environment. -> (EffectRep (DispatchOf e) e -> (EffectRep (DispatchOf e) e)) -> IO () @@ -343,7 +344,7 @@ modifyEnv env f = do -- | Determine location of the effect in the environment. getLocation - :: forall e es. e :> es + :: forall e es. (HasCallStack, e :> es) => Env es -> IO (Int, SmallMutableArray RealWorld Any) getLocation (Env offset refs storage) = do @@ -364,7 +365,7 @@ getLocation (Env offset refs storage) = do -- Internal helpers -- | Create an empty storage. -emptyStorage :: IO Storage +emptyStorage :: HasCallStack => IO Storage emptyStorage = Storage 0 (noVersion + 1) <$> newPrimArray 0 <*> newSmallArray 0 undefinedData @@ -372,7 +373,8 @@ emptyStorage = Storage 0 (noVersion + 1) -- | Insert an effect into the storage and return its reference. insertEffect - :: IORef' Storage + :: HasCallStack + => IORef' Storage -> EffectRep (DispatchOf e) e -- ^ The representation of the effect. -> Relinker (EffectRep (DispatchOf e)) e @@ -404,7 +406,7 @@ insertEffect storage e f = do -- | Given a reference to an effect from the top of the stack, delete it from -- the storage. -deleteEffect :: IORef' Storage -> Int -> IO () +deleteEffect :: HasCallStack => IORef' Storage -> Int -> IO () deleteEffect storage ref = do Storage size version vs es fs <- readIORef' storage when (ref /= size - 1) $ do diff --git a/effectful-core/src/Effectful/Internal/Monad.hs b/effectful-core/src/Effectful/Internal/Monad.hs index 7001436..808f67b 100644 --- a/effectful-core/src/Effectful/Internal/Monad.hs +++ b/effectful-core/src/Effectful/Internal/Monad.hs @@ -129,7 +129,7 @@ newtype Eff (es :: [Effect]) a = Eff (Env es -> IO a) -- | Run a pure 'Eff' computation. -- -- For running computations with side effects see 'runEff'. -runPureEff :: Eff '[] a -> a +runPureEff :: HasCallStack => Eff '[] a -> a runPureEff (Eff m) = -- unsafeDupablePerformIO is safe here since IOE was not on the stack, so no -- IO with side effects was performed (unless someone sneakily introduced side @@ -339,7 +339,7 @@ newtype instance StaticRep IOE = IOE UnliftStrategy -- | Run an 'Eff' computation with side effects. -- -- For running pure computations see 'runPureEff'. -runEff :: Eff '[IOE] a -> IO a +runEff :: HasCallStack => Eff '[IOE] a -> IO a runEff m = unEff m =<< consEnv (IOE SeqUnlift) dummyRelinker =<< emptyEnv instance IOE :> es => MonadIO (Eff es) where @@ -387,7 +387,7 @@ data instance StaticRep Prim = Prim data PrimStateEff -- | Run an 'Eff' computation with primitive state-transformer actions. -runPrim :: IOE :> es => Eff (Prim : es) a -> Eff es a +runPrim :: (HasCallStack, IOE :> es) => Eff (Prim : es) a -> Eff es a runPrim = evalStaticRep Prim instance Prim :> es => PrimMonad (Eff es) where @@ -515,7 +515,11 @@ relinkHandler = Relinker $ \relink (Handler handlerEs handler) -> do pure $ Handler newHandlerEs handler -- | Run a dynamically dispatched effect with the given handler. -runHandler :: DispatchOf e ~ Dynamic => Handler e -> Eff (e : es) a -> Eff es a +runHandler + :: (HasCallStack, DispatchOf e ~ Dynamic) + => Handler e + -> Eff (e : es) a + -> Eff es a runHandler e m = unsafeEff $ \es0 -> do inlineBracket (consEnv e relinkHandler es0) @@ -553,7 +557,7 @@ type instance EffectRep (Static sideEffects) = StaticRep -- | Run a statically dispatched effect with the given initial representation -- and return the final value along with the final representation. runStaticRep - :: (DispatchOf e ~ Static sideEffects, MaybeIOE sideEffects es) + :: (HasCallStack, DispatchOf e ~ Static sideEffects, MaybeIOE sideEffects es) => StaticRep e -- ^ The initial representation. -> Eff (e : es) a -> Eff es (a, StaticRep e) @@ -566,7 +570,7 @@ runStaticRep e0 m = unsafeEff $ \es0 -> do -- | Run a statically dispatched effect with the given initial representation -- and return the final value, discarding the final representation. evalStaticRep - :: (DispatchOf e ~ Static sideEffects, MaybeIOE sideEffects es) + :: (HasCallStack, DispatchOf e ~ Static sideEffects, MaybeIOE sideEffects es) => StaticRep e -- ^ The initial representation. -> Eff (e : es) a -> Eff es a @@ -579,7 +583,7 @@ evalStaticRep e m = unsafeEff $ \es0 -> do -- | Run a statically dispatched effect with the given initial representation -- and return the final representation, discarding the final value. execStaticRep - :: (DispatchOf e ~ Static sideEffects, MaybeIOE sideEffects es) + :: (HasCallStack, DispatchOf e ~ Static sideEffects, MaybeIOE sideEffects es) => StaticRep e -- ^ The initial representation. -> Eff (e : es) a -> Eff es (StaticRep e) @@ -590,17 +594,21 @@ execStaticRep e0 m = unsafeEff $ \es0 -> do (\es -> unEff m es *> getEnv es) -- | Fetch the current representation of the effect. -getStaticRep :: (DispatchOf e ~ Static sideEffects, e :> es) => Eff es (StaticRep e) +getStaticRep + :: (HasCallStack, DispatchOf e ~ Static sideEffects, e :> es) + => Eff es (StaticRep e) getStaticRep = unsafeEff $ \es -> getEnv es -- | Set the current representation of the effect to the given value. -putStaticRep :: (DispatchOf e ~ Static sideEffects, e :> es) => StaticRep e -> Eff es () +putStaticRep + :: (HasCallStack, DispatchOf e ~ Static sideEffects, e :> es) + => StaticRep e -> Eff es () putStaticRep s = unsafeEff $ \es -> putEnv es s -- | Apply the function to the current representation of the effect and return a -- value. stateStaticRep - :: (DispatchOf e ~ Static sideEffects, e :> es) + :: (HasCallStack, DispatchOf e ~ Static sideEffects, e :> es) => (StaticRep e -> (a, StaticRep e)) -- ^ The function to modify the representation. -> Eff es a @@ -609,7 +617,7 @@ stateStaticRep f = unsafeEff $ \es -> stateEnv es f -- | Apply the monadic function to the current representation of the effect and -- return a value. stateStaticRepM - :: (DispatchOf e ~ Static sideEffects, e :> es) + :: (HasCallStack, DispatchOf e ~ Static sideEffects, e :> es) => (StaticRep e -> Eff es (a, StaticRep e)) -- ^ The function to modify the representation. -> Eff es a @@ -621,7 +629,7 @@ stateStaticRepM f = unsafeEff $ \es -> E.mask $ \unmask -> do -- | Execute a computation with a temporarily modified representation of the -- effect. localStaticRep - :: (DispatchOf e ~ Static sideEffects, e :> es) + :: (HasCallStack, DispatchOf e ~ Static sideEffects, e :> es) => (StaticRep e -> StaticRep e) -- ^ The function to temporarily modify the representation. -> Eff es a diff --git a/effectful-core/src/Effectful/Labeled.hs b/effectful-core/src/Effectful/Labeled.hs index 1471f4b..772c6a3 100644 --- a/effectful-core/src/Effectful/Labeled.hs +++ b/effectful-core/src/Effectful/Labeled.hs @@ -51,7 +51,8 @@ data instance StaticRep (Labeled label e) -- | Run a 'Labeled' effect with a given effect handler. runLabeled :: forall label e es a b - . (Eff (e : es) a -> Eff es b) + . HasCallStack + => (Eff (e : es) a -> Eff es b) -- ^ The effect handler. -> Eff (Labeled label e : es) a -> Eff es b @@ -62,7 +63,7 @@ runLabeled runE m = runE (fromLabeled m) -- Useful for running code written with the non-labeled effect in mind. labeled :: forall label e es a - . Labeled label e :> es + . (HasCallStack, Labeled label e :> es) => Eff (e : es) a -- ^ The action using the effect. -> Eff es a diff --git a/effectful-core/src/Effectful/Labeled/Error.hs b/effectful-core/src/Effectful/Labeled/Error.hs index b42d80c..013d93d 100644 --- a/effectful-core/src/Effectful/Labeled/Error.hs +++ b/effectful-core/src/Effectful/Labeled/Error.hs @@ -38,7 +38,8 @@ import Effectful.Error.Dynamic qualified as E -- | Handle errors of type @e@ (via "Effectful.Error.Static"). runError :: forall label e es a - . Eff (Labeled label (Error e) : es) a + . HasCallStack + => Eff (Labeled label (Error e) : es) a -> Eff es (Either (E.CallStack, e) a) runError = runLabeled @label E.runError @@ -46,7 +47,8 @@ runError = runLabeled @label E.runError -- error handler. runErrorWith :: forall label e es a - . (E.CallStack -> e -> Eff es a) + . HasCallStack + => (E.CallStack -> e -> Eff es a) -- ^ The error handler. -> Eff (Labeled label (Error e) : es) a -> Eff es a @@ -56,7 +58,8 @@ runErrorWith = runLabeled @label . E.runErrorWith -- error discard the 'E.CallStack'. runErrorNoCallStack :: forall label e es a - . Eff (Labeled label (Error e) : es) a + . HasCallStack + => Eff (Labeled label (Error e) : es) a -> Eff es (Either e a) runErrorNoCallStack = runLabeled @label E.runErrorNoCallStack @@ -64,7 +67,8 @@ runErrorNoCallStack = runLabeled @label E.runErrorNoCallStack -- error handler. In case of an error discard the 'CallStack'. runErrorNoCallStackWith :: forall label e es a - . (e -> Eff es a) + . HasCallStack + => (e -> Eff es a) -- ^ The error handler. -> Eff (Labeled label (Error e) : es) a -> Eff es a diff --git a/effectful-core/src/Effectful/Labeled/Reader.hs b/effectful-core/src/Effectful/Labeled/Reader.hs index 3652295..adc991f 100644 --- a/effectful-core/src/Effectful/Labeled/Reader.hs +++ b/effectful-core/src/Effectful/Labeled/Reader.hs @@ -25,7 +25,8 @@ import Effectful.Reader.Dynamic qualified as R -- "Effectful.Reader.Static"). runReader :: forall label r es a - . r + . HasCallStack + => r -- ^ The initial environment. -> Eff (Labeled label (Reader r) : es) a -> Eff es a diff --git a/effectful-core/src/Effectful/Labeled/State.hs b/effectful-core/src/Effectful/Labeled/State.hs index fabd909..93f2280 100644 --- a/effectful-core/src/Effectful/Labeled/State.hs +++ b/effectful-core/src/Effectful/Labeled/State.hs @@ -41,7 +41,8 @@ import Effectful.State.Dynamic qualified as S -- value along with the final state (via "Effectful.State.Static.Local"). runStateLocal :: forall label s es a - . s + . HasCallStack + => s -- ^ The initial state. -> Eff (Labeled label (State s) : es) a -> Eff es (a, s) @@ -51,7 +52,8 @@ runStateLocal = runLabeled @label . S.runStateLocal -- value, discarding the final state (via "Effectful.State.Static.Local"). evalStateLocal :: forall label s es a - . s + . HasCallStack + => s -- ^ The initial state. -> Eff (Labeled label (State s) : es) a -> Eff es a @@ -61,7 +63,8 @@ evalStateLocal = runLabeled @label . S.evalStateLocal -- state, discarding the final value (via "Effectful.State.Static.Local"). execStateLocal :: forall label s es a - . s + . HasCallStack + => s -- ^ The initial state. -> Eff (Labeled label (State s) : es) a -> Eff es s @@ -74,7 +77,8 @@ execStateLocal = runLabeled @label . S.execStateLocal -- value along with the final state (via "Effectful.State.Static.Shared"). runStateShared :: forall label s es a - . s + . HasCallStack + => s -- ^ The initial state. -> Eff (Labeled label (State s) : es) a -> Eff es (a, s) @@ -84,7 +88,8 @@ runStateShared = runLabeled @label . S.runStateShared -- value, discarding the final state (via "Effectful.State.Static.Shared"). evalStateShared :: forall label s es a - . s + . HasCallStack + => s -- ^ The initial state. -> Eff (Labeled label (State s) : es) a -> Eff es a @@ -94,7 +99,8 @@ evalStateShared = runLabeled @label . S.evalStateShared -- state, discarding the final value (via "Effectful.State.Static.Shared"). execStateShared :: forall label s es a - . s + . HasCallStack + => s -- ^ The initial state. -> Eff (Labeled label (State s) : es) a -> Eff es s diff --git a/effectful-core/src/Effectful/Labeled/Writer.hs b/effectful-core/src/Effectful/Labeled/Writer.hs index c23f206..13f3176 100644 --- a/effectful-core/src/Effectful/Labeled/Writer.hs +++ b/effectful-core/src/Effectful/Labeled/Writer.hs @@ -35,7 +35,7 @@ import Effectful.Writer.Dynamic qualified as W -- output (via "Effectful.Writer.Static.Local"). runWriterLocal :: forall label w es a - . Monoid w + . (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es (a, w) runWriterLocal = runLabeled @label W.runWriterLocal @@ -44,7 +44,7 @@ runWriterLocal = runLabeled @label W.runWriterLocal -- value (via "Effectful.Writer.Static.Local"). execWriterLocal :: forall label w es a - . Monoid w + . (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es w execWriterLocal = runLabeled @label W.execWriterLocal @@ -56,7 +56,7 @@ execWriterLocal = runLabeled @label W.execWriterLocal -- output (via "Effectful.Writer.Static.Shared"). runWriterShared :: forall label w es a - . Monoid w + . (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es (a, w) runWriterShared = runLabeled @label W.runWriterShared @@ -65,7 +65,7 @@ runWriterShared = runLabeled @label W.runWriterShared -- value (via "Effectful.Writer.Static.Shared"). execWriterShared :: forall label w es a - . Monoid w + . (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es w execWriterShared = runLabeled @label W.execWriterShared diff --git a/effectful-core/src/Effectful/NonDet.hs b/effectful-core/src/Effectful/NonDet.hs index fd8ce35..a41b61d 100644 --- a/effectful-core/src/Effectful/NonDet.hs +++ b/effectful-core/src/Effectful/NonDet.hs @@ -50,12 +50,19 @@ data OnEmptyPolicy -- computation calls 'Empty'. -- -- @since 2.2.0.0 -runNonDet :: OnEmptyPolicy -> Eff (NonDet : es) a -> Eff es (Either CallStack a) +runNonDet + :: HasCallStack + => OnEmptyPolicy + -> Eff (NonDet : es) a + -> Eff es (Either CallStack a) runNonDet = \case OnEmptyKeep -> runNonDetKeep OnEmptyRollback -> runNonDetRollback -runNonDetKeep :: Eff (NonDet : es) a -> Eff es (Either CallStack a) +runNonDetKeep + :: HasCallStack + => Eff (NonDet : es) a + -> Eff es (Either CallStack a) runNonDetKeep = reinterpret (fmap noError . runError @()) $ \env -> \case Empty -> throwError () m1 :<|>: m2 -> localSeqUnlift env $ \unlift -> do @@ -64,7 +71,10 @@ runNonDetKeep = reinterpret (fmap noError . runError @()) $ \env -> \case Just r -> pure r Nothing -> unlift m2 -runNonDetRollback :: Eff (NonDet : es) a -> Eff es (Either CallStack a) +runNonDetRollback + :: HasCallStack + => Eff (NonDet : es) a + -> Eff es (Either CallStack a) runNonDetRollback = reinterpret (fmap noError . runError @()) $ \env -> \case Empty -> throwError () m1 :<|>: m2 -> do diff --git a/effectful-core/src/Effectful/Provider.hs b/effectful-core/src/Effectful/Provider.hs index 1b8d947..549d5e2 100644 --- a/effectful-core/src/Effectful/Provider.hs +++ b/effectful-core/src/Effectful/Provider.hs @@ -128,7 +128,8 @@ data instance StaticRep (Provider e input f) where -- | Run the 'Provider' effect with a given effect handler. runProvider - :: (forall r. input -> Eff (e : es) r -> Eff es (f r)) + :: HasCallStack + => (forall r. input -> Eff (e : es) r -> Eff es (f r)) -- ^ The effect handler. -> Eff (Provider e input f : es) a -> Eff es a @@ -141,23 +142,24 @@ runProvider run m = unsafeEff $ \es0 -> do -- | Run the 'Provider' effect with a given effect handler that doesn't change -- its return type. runProvider_ - :: (forall r. input -> Eff (e : es) r -> Eff es r) + :: HasCallStack + => (forall r. input -> Eff (e : es) r -> Eff es r) -- ^ The effect handler. -> Eff (Provider_ e input : es) a -> Eff es a runProvider_ run = runProvider $ \input -> coerce . run input -- | Run the effect handler. -provide :: Provider e () f :> es => Eff (e : es) a -> Eff es (f a) +provide :: (HasCallStack, Provider e () f :> es) => Eff (e : es) a -> Eff es (f a) provide = provideWith () -- | Run the effect handler with unchanged return type. -provide_ :: Provider_ e () :> es => Eff (e : es) a -> Eff es a +provide_ :: (HasCallStack, Provider_ e () :> es) => Eff (e : es) a -> Eff es a provide_ = provideWith_ () -- | Run the effect handler with a given input. provideWith - :: Provider e input f :> es + :: (HasCallStack, Provider e input f :> es) => input -- ^ The input to the effect handler. -> Eff (e : es) a @@ -170,7 +172,7 @@ provideWith input action = unsafeEff $ \es -> do -- | Run the effect handler that doesn't change its return type with a given -- input. provideWith_ - :: Provider_ e input :> es + :: (HasCallStack, Provider_ e input :> es) => input -- ^ The input to the effect handler. -> Eff (e : es) a @@ -188,7 +190,7 @@ relinkProvider = Relinker $ \relink (Provider handlerEs run) -> do newHandlerEs <- relink handlerEs pure $ Provider newHandlerEs run -copyRef :: Env (e : handlerEs) -> Env es -> IO (Env (e : es)) +copyRef :: HasCallStack => Env (e : handlerEs) -> Env es -> IO (Env (e : es)) copyRef (Env hoffset hrefs hstorage) (Env offset refs0 storage) = do when (hstorage /= storage) $ do error "storages do not match" diff --git a/effectful-core/src/Effectful/Provider/List.hs b/effectful-core/src/Effectful/Provider/List.hs index b593e91..29a280c 100644 --- a/effectful-core/src/Effectful/Provider/List.hs +++ b/effectful-core/src/Effectful/Provider/List.hs @@ -57,7 +57,7 @@ data instance StaticRep (ProviderList effs input f) where -- | Run the 'ProviderList' effect with a given handler. runProviderList - :: KnownEffects effs + :: (HasCallStack, KnownEffects effs) => (forall r. input -> Eff (effs ++ es) r -> Eff es (f r)) -- ^ The handler. -> Eff (ProviderList effs input f : es) a @@ -71,7 +71,7 @@ runProviderList run m = unsafeEff $ \es0 -> do -- | Run the 'Provider' effect with a given handler that doesn't change its -- return type. runProviderList_ - :: KnownEffects effs + :: (HasCallStack, KnownEffects effs) => (forall r. input -> Eff (effs ++ es) r -> Eff es r) -- ^ The handler. -> Eff (ProviderList_ effs input : es) a @@ -81,7 +81,7 @@ runProviderList_ run = runProviderList $ \input -> coerce . run input -- | Run the handler. provideList :: forall effs f es a - . ProviderList effs () f :> es + . (HasCallStack, ProviderList effs () f :> es) => Eff (effs ++ es) a -> Eff es (f a) provideList = provideListWith @effs () @@ -89,7 +89,7 @@ provideList = provideListWith @effs () -- | Run the handler with unchanged return type. provideList_ :: forall effs es a - . ProviderList_ effs () :> es + . (HasCallStack, ProviderList_ effs () :> es) => Eff (effs ++ es) a -> Eff es a provideList_ = provideListWith_ @effs () @@ -97,7 +97,7 @@ provideList_ = provideListWith_ @effs () -- | Run the handler with a given input. provideListWith :: forall effs input f es a - . ProviderList effs input f :> es + . (HasCallStack, ProviderList effs input f :> es) => input -- ^ The input to the handler. -> Eff (effs ++ es) a @@ -110,7 +110,7 @@ provideListWith input action = unsafeEff $ \es -> do -- | Run the handler that doesn't change its return type with a given input. provideListWith_ :: forall effs input es a - . ProviderList_ effs input :> es + . (HasCallStack, ProviderList_ effs input :> es) => input -- ^ The input to the handler. -> Eff (effs ++ es) a @@ -130,7 +130,7 @@ relinkProviderList = Relinker $ \relink (ProviderList handlerEs run) -> do copyRefs :: forall effs handlerEs es - . KnownEffects effs + . (HasCallStack, KnownEffects effs) => Env (effs ++ handlerEs) -> Env es -> IO (Env (effs ++ es)) diff --git a/effectful-core/src/Effectful/Reader/Dynamic.hs b/effectful-core/src/Effectful/Reader/Dynamic.hs index 5d51e8b..e1f35dd 100644 --- a/effectful-core/src/Effectful/Reader/Dynamic.hs +++ b/effectful-core/src/Effectful/Reader/Dynamic.hs @@ -30,7 +30,8 @@ type instance DispatchOf (Reader r) = Dynamic -- | Run the 'Reader' effect with the given initial environment (via -- "Effectful.Reader.Static"). runReader - :: r -- ^ The initial environment. + :: HasCallStack + => r -- ^ The initial environment. -> Eff (Reader r : es) a -> Eff es a runReader r = reinterpret (R.runReader r) $ \env -> \case @@ -41,7 +42,8 @@ runReader r = reinterpret (R.runReader r) $ \env -> \case -- -- @since 1.1.0.0 withReader - :: (r1 -> r2) + :: HasCallStack + => (r1 -> r2) -- ^ The function to modify the environment. -> Eff (Reader r2 : es) a -- ^ Computation to run in the modified environment. diff --git a/effectful-core/src/Effectful/Reader/Static.hs b/effectful-core/src/Effectful/Reader/Static.hs index 9b50e45..d3dd2fe 100644 --- a/effectful-core/src/Effectful/Reader/Static.hs +++ b/effectful-core/src/Effectful/Reader/Static.hs @@ -27,7 +27,8 @@ newtype instance StaticRep (Reader r) = Reader r -- | Run a 'Reader' effect with the given initial environment. runReader - :: r -- ^ The initial environment. + :: HasCallStack + => r -- ^ The initial environment. -> Eff (Reader r : es) a -> Eff es a runReader r = evalStaticRep (Reader r) @@ -36,7 +37,8 @@ runReader r = evalStaticRep (Reader r) -- -- @since 1.1.0.0 withReader - :: (r1 -> r2) + :: HasCallStack + => (r1 -> r2) -- ^ The function to modify the environment. -> Eff (Reader r2 : es) a -- ^ Computation to run in the modified environment. @@ -46,7 +48,7 @@ withReader f m = do raise $ runReader (f r) m -- | Fetch the value of the environment. -ask :: Reader r :> es => Eff es r +ask :: (HasCallStack, Reader r :> es) => Eff es r ask = do Reader r <- getStaticRep pure r @@ -55,7 +57,7 @@ ask = do -- -- @'asks' f ≡ f '<$>' 'ask'@ asks - :: Reader r :> es + :: (HasCallStack, Reader r :> es) => (r -> a) -- ^ The function to apply to the environment. -> Eff es a asks f = f <$> ask @@ -65,7 +67,7 @@ asks f = f <$> ask -- @'runReader' r ('local' f m) ≡ 'runReader' (f r) m@ -- local - :: Reader r :> es + :: (HasCallStack, Reader r :> es) => (r -> r) -- ^ The function to modify the environment. -> Eff es a -> Eff es a diff --git a/effectful-core/src/Effectful/State/Dynamic.hs b/effectful-core/src/Effectful/State/Dynamic.hs index 613b379..715649a 100644 --- a/effectful-core/src/Effectful/State/Dynamic.hs +++ b/effectful-core/src/Effectful/State/Dynamic.hs @@ -48,24 +48,20 @@ type instance DispatchOf (State s) = Dynamic -- | Run the 'State' effect with the given initial state and return the final -- value along with the final state (via "Effectful.State.Static.Local"). -runStateLocal :: s -> Eff (State s : es) a -> Eff es (a, s) +runStateLocal :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s) runStateLocal s0 = reinterpret (L.runState s0) localState -- | Run the 'State' effect with the given initial state and return the final -- value, discarding the final state (via "Effectful.State.Static.Local"). -evalStateLocal :: s -> Eff (State s : es) a -> Eff es a +evalStateLocal :: HasCallStack => s -> Eff (State s : es) a -> Eff es a evalStateLocal s0 = reinterpret (L.evalState s0) localState -- | Run the 'State' effect with the given initial state and return the final -- state, discarding the final value (via "Effectful.State.Static.Local"). -execStateLocal :: s -> Eff (State s : es) a -> Eff es s +execStateLocal :: HasCallStack => s -> Eff (State s : es) a -> Eff es s execStateLocal s0 = reinterpret (L.execState s0) localState -localState - :: L.State s :> es - => LocalEnv localEs es - -> State s (Eff localEs) a - -> Eff es a +localState :: L.State s :> es => EffectHandler (State s) es localState env = \case Get -> L.get Put s -> L.put s @@ -77,24 +73,20 @@ localState env = \case -- | Run the 'State' effect with the given initial state and return the final -- value along with the final state (via "Effectful.State.Static.Shared"). -runStateShared :: s -> Eff (State s : es) a -> Eff es (a, s) +runStateShared :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s) runStateShared s0 = reinterpret (S.runState s0) sharedState -- | Run the 'State' effect with the given initial state and return the final -- value, discarding the final state (via "Effectful.State.Static.Shared"). -evalStateShared :: s -> Eff (State s : es) a -> Eff es a +evalStateShared :: HasCallStack => s -> Eff (State s : es) a -> Eff es a evalStateShared s0 = reinterpret (S.evalState s0) sharedState -- | Run the 'State' effect with the given initial state and return the final -- state, discarding the final value (via "Effectful.State.Static.Shared"). -execStateShared :: s -> Eff (State s : es) a -> Eff es s +execStateShared :: HasCallStack => s -> Eff (State s : es) a -> Eff es s execStateShared s0 = reinterpret (S.execState s0) sharedState -sharedState - :: S.State s :> es - => LocalEnv localEs es - -> State s (Eff localEs) a - -> Eff es a +sharedState :: S.State s :> es => EffectHandler (State s) es sharedState env = \case Get -> S.get Put s -> S.put s diff --git a/effectful-core/src/Effectful/State/Static/Local.hs b/effectful-core/src/Effectful/State/Static/Local.hs index c23a7eb..d08da06 100644 --- a/effectful-core/src/Effectful/State/Static/Local.hs +++ b/effectful-core/src/Effectful/State/Static/Local.hs @@ -55,7 +55,8 @@ newtype instance StaticRep (State s) = State s -- | Run the 'State' effect with the given initial state and return the final -- value along with the final state. runState - :: s -- ^ The initial state. + :: HasCallStack + => s -- ^ The initial state. -> Eff (State s : es) a -> Eff es (a, s) runState s0 m = do @@ -65,7 +66,8 @@ runState s0 m = do -- | Run the 'State' effect with the given initial state and return the final -- value, discarding the final state. evalState - :: s -- ^ The initial state. + :: HasCallStack + => s -- ^ The initial state. -> Eff (State s : es) a -> Eff es a evalState s = evalStaticRep (State s) @@ -73,7 +75,8 @@ evalState s = evalStaticRep (State s) -- | Run the 'State' effect with the given initial state and return the final -- state, discarding the final value. execState - :: s -- ^ The initial state. + :: HasCallStack + => s -- ^ The initial state. -> Eff (State s : es) a -> Eff es s execState s0 m = do @@ -81,7 +84,7 @@ execState s0 m = do pure s -- | Fetch the current value of the state. -get :: State s :> es => Eff es s +get :: (HasCallStack, State s :> es) => Eff es s get = do State s <- getStaticRep pure s @@ -90,18 +93,18 @@ get = do -- -- @'gets' f ≡ f '<$>' 'get'@ gets - :: State s :> es + :: (HasCallStack, State s :> es) => (s -> a) -- ^ The function to apply to the state. -> Eff es a gets f = f <$> get -- | Set the current state to the given value. -put :: State s :> es => s -> Eff es () +put :: (HasCallStack, State s :> es) => s -> Eff es () put s = putStaticRep (State s) -- | Apply the function to the current state and return a value. state - :: State s :> es + :: (HasCallStack, State s :> es) => (s -> (a, s)) -- ^ The function to modify the state. -> Eff es a state f = stateStaticRep $ \(State s0) -> let (a, s) = f s0 in (a, State s) @@ -110,14 +113,14 @@ state f = stateStaticRep $ \(State s0) -> let (a, s) = f s0 in (a, State s) -- -- @'modify' f ≡ 'state' (\\s -> ((), f s))@ modify - :: State s :> es + :: (HasCallStack, State s :> es) => (s -> s) -- ^ The function to modify the state. -> Eff es () modify f = state $ \s -> ((), f s) -- | Apply the monadic function to the current state and return a value. stateM - :: State s :> es + :: (HasCallStack, State s :> es) => (s -> Eff es (a, s)) -- ^ The function to modify the state. -> Eff es a stateM f = stateStaticRepM $ \(State s0) -> do @@ -128,7 +131,7 @@ stateM f = stateStaticRepM $ \(State s0) -> do -- -- @'modifyM' f ≡ 'stateM' (\\s -> ((), ) '<$>' f s)@ modifyM - :: State s :> es + :: (HasCallStack, State s :> es) => (s -> Eff es s) -- ^ The monadic function to modify the state. -> Eff es () modifyM f = stateM (\s -> ((), ) <$> f s) diff --git a/effectful-core/src/Effectful/State/Static/Shared.hs b/effectful-core/src/Effectful/State/Static/Shared.hs index ffc80ba..1f72504 100644 --- a/effectful-core/src/Effectful/State/Static/Shared.hs +++ b/effectful-core/src/Effectful/State/Static/Shared.hs @@ -60,7 +60,7 @@ newtype instance StaticRep (State s) = State (MVar' s) -- | Run the 'State' effect with the given initial state and return the final -- value along with the final state. -runState :: s -> Eff (State s : es) a -> Eff es (a, s) +runState :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s) runState s m = do v <- unsafeEff_ $ newMVar' s a <- evalStaticRep (State v) m @@ -68,14 +68,14 @@ runState s m = do -- | Run the 'State' effect with the given initial state and return the final -- value, discarding the final state. -evalState :: s -> Eff (State s : es) a -> Eff es a +evalState :: HasCallStack => s -> Eff (State s : es) a -> Eff es a evalState s m = do v <- unsafeEff_ $ newMVar' s evalStaticRep (State v) m -- | Run the 'State' effect with the given initial state and return the final -- state, discarding the final value. -execState :: s -> Eff (State s : es) a -> Eff es s +execState :: HasCallStack => s -> Eff (State s : es) a -> Eff es s execState s m = do v <- unsafeEff_ $ newMVar' s _ <- evalStaticRep (State v) m @@ -83,25 +83,25 @@ execState s m = do -- | Run the 'State' effect with the given initial state 'MVar'' and return the -- final value along with the final state. -runStateMVar :: MVar' s -> Eff (State s : es) a -> Eff es (a, s) +runStateMVar :: HasCallStack => MVar' s -> Eff (State s : es) a -> Eff es (a, s) runStateMVar v m = do a <- evalStaticRep (State v) m (a, ) <$> unsafeEff_ (readMVar' v) -- | Run the 'State' effect with the given initial state 'MVar'' and return the -- final value, discarding the final state. -evalStateMVar :: MVar' s -> Eff (State s : es) a -> Eff es a +evalStateMVar :: HasCallStack => MVar' s -> Eff (State s : es) a -> Eff es a evalStateMVar v = evalStaticRep (State v) -- | Run the 'State' effect with the given initial state 'MVar'' and return the -- final state, discarding the final value. -execStateMVar :: MVar' s -> Eff (State s : es) a -> Eff es s +execStateMVar :: HasCallStack => MVar' s -> Eff (State s : es) a -> Eff es s execStateMVar v m = do _ <- evalStaticRep (State v) m unsafeEff_ $ readMVar' v -- | Fetch the current value of the state. -get :: State s :> es => Eff es s +get :: (HasCallStack, State s :> es) => Eff es s get = unsafeEff $ \es -> do State v <- getEnv es readMVar' v @@ -109,11 +109,11 @@ get = unsafeEff $ \es -> do -- | Get a function of the current state. -- -- @'gets' f ≡ f '<$>' 'get'@ -gets :: State s :> es => (s -> a) -> Eff es a +gets :: (HasCallStack, State s :> es) => (s -> a) -> Eff es a gets f = f <$> get -- | Set the current state to the given value. -put :: State s :> es => s -> Eff es () +put :: (HasCallStack, State s :> es) => s -> Eff es () put s = unsafeEff $ \es -> do State v <- getEnv es modifyMVar'_ v $ \_ -> pure s @@ -121,7 +121,7 @@ put s = unsafeEff $ \es -> do -- | Apply the function to the current state and return a value. -- -- /Note:/ this function gets an exclusive access to the state for its duration. -state :: State s :> es => (s -> (a, s)) -> Eff es a +state :: (HasCallStack, State s :> es) => (s -> (a, s)) -> Eff es a state f = unsafeEff $ \es -> do State v <- getEnv es modifyMVar' v $ \s0 -> let (a, s) = f s0 in pure (s, a) @@ -131,13 +131,13 @@ state f = unsafeEff $ \es -> do -- @'modify' f ≡ 'state' (\\s -> ((), f s))@ -- -- /Note:/ this function gets an exclusive access to the state for its duration. -modify :: State s :> es => (s -> s) -> Eff es () +modify :: (HasCallStack, State s :> es) => (s -> s) -> Eff es () modify f = state (\s -> ((), f s)) -- | Apply the monadic function to the current state and return a value. -- -- /Note:/ this function gets an exclusive access to the state for its duration. -stateM :: State s :> es => (s -> Eff es (a, s)) -> Eff es a +stateM :: (HasCallStack, State s :> es) => (s -> Eff es (a, s)) -> Eff es a stateM f = unsafeEff $ \es -> do State v <- getEnv es modifyMVar' v $ \s0 -> do @@ -149,7 +149,7 @@ stateM f = unsafeEff $ \es -> do -- @'modifyM' f ≡ 'stateM' (\\s -> ((), ) '<$>' f s)@ -- -- /Note:/ this function gets an exclusive access to the state for its duration. -modifyM :: State s :> es => (s -> Eff es s) -> Eff es () +modifyM :: (HasCallStack, State s :> es) => (s -> Eff es s) -> Eff es () modifyM f = stateM (\s -> ((), ) <$> f s) -- $setup diff --git a/effectful-core/src/Effectful/Writer/Dynamic.hs b/effectful-core/src/Effectful/Writer/Dynamic.hs index 78ee6df..00e6414 100644 --- a/effectful-core/src/Effectful/Writer/Dynamic.hs +++ b/effectful-core/src/Effectful/Writer/Dynamic.hs @@ -40,19 +40,15 @@ type instance DispatchOf (Writer w) = Dynamic -- | Run the 'Writer' effect and return the final value along with the final -- output (via "Effectful.Writer.Static.Local"). -runWriterLocal :: Monoid w => Eff (Writer w : es) a -> Eff es (a, w) +runWriterLocal :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) runWriterLocal = reinterpret L.runWriter localWriter -- | Run a 'Writer' effect and return the final output, discarding the final -- value (via "Effectful.Writer.Static.Local"). -execWriterLocal :: Monoid w => Eff (Writer w : es) a -> Eff es w +execWriterLocal :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w execWriterLocal = reinterpret L.execWriter localWriter -localWriter - :: (L.Writer w :> es, Monoid w) - => LocalEnv localEs es - -> Writer w (Eff localEs) a - -> Eff es a +localWriter :: (L.Writer w :> es, Monoid w) => EffectHandler (Writer w) es localWriter env = \case Tell w -> L.tell w Listen m -> localSeqUnlift env $ \unlift -> L.listen (unlift m) @@ -62,19 +58,15 @@ localWriter env = \case -- | Run the 'Writer' effect and return the final value along with the final -- output (via "Effectful.Writer.Static.Shared"). -runWriterShared :: Monoid w => Eff (Writer w : es) a -> Eff es (a, w) +runWriterShared :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) runWriterShared = reinterpret S.runWriter sharedWriter -- | Run the 'Writer' effect and return the final output, discarding the final -- value (via "Effectful.Writer.Static.Shared"). -execWriterShared :: Monoid w => Eff (Writer w : es) a -> Eff es w +execWriterShared :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w execWriterShared = reinterpret S.execWriter sharedWriter -sharedWriter - :: (S.Writer w :> es, Monoid w) - => LocalEnv localEs es - -> Writer w (Eff localEs) a - -> Eff es a +sharedWriter :: (S.Writer w :> es, Monoid w) => EffectHandler (Writer w) es sharedWriter env = \case Tell w -> S.tell w Listen m -> localSeqUnlift env $ \unlift -> S.listen (unlift m) diff --git a/effectful-core/src/Effectful/Writer/Static/Local.hs b/effectful-core/src/Effectful/Writer/Static/Local.hs index 8995144..1a4d9a5 100644 --- a/effectful-core/src/Effectful/Writer/Static/Local.hs +++ b/effectful-core/src/Effectful/Writer/Static/Local.hs @@ -43,20 +43,20 @@ newtype instance StaticRep (Writer w) = Writer w -- | Run a 'Writer' effect and return the final value along with the final -- output. -runWriter :: Monoid w => Eff (Writer w : es) a -> Eff es (a, w) +runWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) runWriter m = do (a, Writer w) <- runStaticRep (Writer mempty) m pure (a, w) -- | Run a 'Writer' effect and return the final output, discarding the final -- value. -execWriter :: Monoid w => Eff (Writer w : es) a -> Eff es w +execWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w execWriter m = do Writer w <- execStaticRep (Writer mempty) m pure w -- | Append the given output to the overall output of the 'Writer'. -tell :: (Writer w :> es, Monoid w) => w -> Eff es () +tell :: (HasCallStack, Writer w :> es, Monoid w) => w -> Eff es () tell w = stateStaticRep $ \(Writer w0) -> ((), Writer (w0 <> w)) -- | Execute an action and append its output to the overall output of the @@ -76,7 +76,7 @@ tell w = stateStaticRep $ \(Writer w0) -> ((), Writer (w0 <> w)) -- error "oops" -- :} -- "Hi there!" -listen :: (Writer w :> es, Monoid w) => Eff es a -> Eff es (a, w) +listen :: (HasCallStack, Writer w :> es, Monoid w) => Eff es a -> Eff es (a, w) listen m = unsafeEff $ \es -> mask $ \unmask -> do w0 <- stateEnv es $ \(Writer w) -> (w, Writer mempty) a <- unmask (unEff m es) `onException` merge es w0 @@ -91,7 +91,11 @@ listen m = unsafeEff $ \es -> mask $ \unmask -> do -- output. -- -- @'listens' f m ≡ 'Data.Bifunctor.second' f '<$>' 'listen' m@ -listens :: (Writer w :> es, Monoid w) => (w -> b) -> Eff es a -> Eff es (a, b) +listens + :: (HasCallStack, Writer w :> es, Monoid w) + => (w -> b) + -> Eff es a + -> Eff es (a, b) listens f m = do (a, w) <- listen m pure (a, f w) diff --git a/effectful-core/src/Effectful/Writer/Static/Shared.hs b/effectful-core/src/Effectful/Writer/Static/Shared.hs index c078f23..37d1df5 100644 --- a/effectful-core/src/Effectful/Writer/Static/Shared.hs +++ b/effectful-core/src/Effectful/Writer/Static/Shared.hs @@ -43,7 +43,7 @@ newtype instance StaticRep (Writer w) = Writer (MVar' w) -- | Run a 'Writer' effect and return the final value along with the final -- output. -runWriter :: Monoid w => Eff (Writer w : es) a -> Eff es (a, w) +runWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) runWriter m = do v <- unsafeEff_ $ newMVar' mempty a <- evalStaticRep (Writer v) m @@ -51,14 +51,14 @@ runWriter m = do -- | Run a 'Writer' effect and return the final output, discarding the final -- value. -execWriter :: Monoid w => Eff (Writer w : es) a -> Eff es w +execWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w execWriter m = do v <- unsafeEff_ $ newMVar' mempty _ <- evalStaticRep (Writer v) m unsafeEff_ $ readMVar' v -- | Append the given output to the overall output of the 'Writer'. -tell :: (Writer w :> es, Monoid w) => w -> Eff es () +tell :: (HasCallStack, Writer w :> es, Monoid w) => w -> Eff es () tell w1 = unsafeEff $ \es -> do Writer v <- getEnv es modifyMVar'_ v $ \w0 -> let w = w0 <> w1 in pure w @@ -80,7 +80,7 @@ tell w1 = unsafeEff $ \es -> do -- error "oops" -- :} -- "Hi there!" -listen :: (Writer w :> es, Monoid w) => Eff es a -> Eff es (a, w) +listen :: (HasCallStack, Writer w :> es, Monoid w) => Eff es a -> Eff es (a, w) listen m = unsafeEff $ \es -> do -- The mask is uninterruptible because modifyMVar_ v0 in the merge function -- might block and if an async exception is received while waiting, w1 will be @@ -105,7 +105,11 @@ listen m = unsafeEff $ \es -> do -- output. -- -- @'listens' f m ≡ 'Data.Bifunctor.second' f '<$>' 'listen' m@ -listens :: (Writer w :> es, Monoid w) => (w -> b) -> Eff es a -> Eff es (a, b) +listens + :: (HasCallStack, Writer w :> es, Monoid w) + => (w -> b) + -> Eff es a + -> Eff es (a, b) listens f m = do (a, w) <- listen m pure (a, f w) diff --git a/effectful-plugin/src-legacy/Effectful/Plugin.hs b/effectful-plugin/src-legacy/Effectful/Plugin.hs index 1d46d42..a0ff33d 100644 --- a/effectful-plugin/src-legacy/Effectful/Plugin.hs +++ b/effectful-plugin/src-legacy/Effectful/Plugin.hs @@ -13,6 +13,7 @@ import GHC.TcPluginM.Extra (lookupModule, lookupName) #if __GLASGOW_HASKELL__ >= 900 import GHC.Core.Class (Class) import GHC.Core.InstEnv (InstEnvs, lookupInstEnv) +import GHC.Core.Predicate (isIPClass) import GHC.Core.Unify (tcUnifyTy) import GHC.Plugins ( Outputable (ppr), Plugin (pluginRecompile, tcPlugin), PredType @@ -46,6 +47,7 @@ import GhcPlugins , tyConClass_maybe ) import InstEnv (InstEnvs, lookupInstEnv) +import Predicate (isIPClass) import TcEnv (tcGetInstEnvs) import TcPluginM (tcLookupClass, tcPluginIO) import TcRnTypes @@ -145,7 +147,7 @@ solveFakedep (elemCls, visitedRef) allGivens allWanteds = do -- We store a list of the types of all given constraints, which will be useful later. allGivenTypes = ctPred <$> allGivens -- We also store a list of wanted constraints that are /not/ 'Elem e es' for later use. - extraWanteds = ctPred <$> filter irrelevant allWanteds + extraWanteds = ctPred <$> filter (\w -> irrelevant w && not (isIP w)) allWanteds -- traceM $ "Givens: " <> show (showSDocUnsafe . ppr <$> allGivens) -- traceM $ "Wanteds: " <> show (showSDocUnsafe . ppr <$> allWanteds) @@ -224,9 +226,15 @@ solveFakedep (elemCls, visitedRef) allGivens allWanteds = do | cls == elemCls = Just $ FakedepWanted (FakedepGiven (fst $ splitAppTys eff) eff es) loc relevantWanted _ = Nothing + -- Check if a constraint in an implicit parameter. + isIP :: Ct -> Bool + isIP = \case + CDictCan _ cls _ _ -> isIPClass cls + _ -> False + -- Determine whether a constraint is /not/ of form 'Elem e es'. irrelevant :: Ct -> Bool - irrelevant = isNothing . relevantGiven + irrelevant = isNothing . relevantWanted -- Given a wanted constraint and a given constraint, unify them and give back a substitution that can be applied -- to the wanted to make it equal to the given. diff --git a/effectful-plugin/src/Effectful/Plugin.hs b/effectful-plugin/src/Effectful/Plugin.hs index 773a636..2f0853f 100644 --- a/effectful-plugin/src/Effectful/Plugin.hs +++ b/effectful-plugin/src/Effectful/Plugin.hs @@ -11,6 +11,7 @@ import Data.Traversable import GHC.Core.Class (Class) import GHC.Core.InstEnv (InstEnvs, lookupInstEnv) +import GHC.Core.Predicate (isIPClass) import GHC.Core.TyCo.Rep (PredType, Type) import GHC.Core.TyCo.Subst import GHC.Core.TyCon (tyConClass_maybe) @@ -167,7 +168,11 @@ solveFakedep (elemCls, visitedRef) _ allGivens allWanteds = do -- constraints. Therefore, we extract these constraints out of the -- 'allGivens' and 'allWanted's. effGivens = mapMaybe maybeEffGiven allGivens - (otherWantedTys, effWanteds) = partitionEithers $ map splitWanteds allWanteds + (otherWantedTys, effWanteds) = partitionEithers + . map splitWanteds + -- Get rid of implicit parameters, they're weird. + . filter (not . isIP) + $ allWanteds -- We store a list of the types of all given constraints, which will be -- useful later. @@ -241,6 +246,16 @@ solveFakedep (elemCls, visitedRef) _ allGivens allWanteds = do else Nothing _ -> Nothing + -- Check if a constraint in an implicit parameter. + isIP :: Ct -> Bool + isIP = \case +#if __GLASGOW_HASKELL__ < 908 + CDictCan { cc_class = cls } -> isIPClass cls +#else + CDictCan DictCt { di_cls = cls } -> isIPClass cls +#endif + _ -> False + -- Determine whether a wanted constraint is of form 'e :> es'. splitWanteds :: Ct -> Either PredType EffWanted splitWanteds = \case