alternators 0.1.2.0 → 1.0.0.0
raw patch · 8 files changed
+298/−119 lines, 8 filesdep +lensdep +mtldep +newtype-genericsdep ~mmorphdep ~transformersPVP ok
version bump matches the API change (PVP)
Dependencies added: lens, mtl, newtype-generics, stm
Dependency ranges changed: mmorph, transformers
API changes (from Hackage documentation)
- Control.Monad.Trans.Maybe.Extras: fromMaybeT :: (Alternative t, Functor m) => MaybeT m a -> m (t a)
- Control.Monad.Trans.Reader.Extras: runReaderM :: (Monad m, Monad (t m), MonadTrans t, MFunctor t) => ReaderT a (t Identity) c -> m a -> t m c
- Control.Monad.Trans.Reader.Extras: runReaderM' :: (Monad m, Monad (t m), MonadTrans t, MFunctor t) => ReaderT a m c -> (t Identity) a -> t m c
- Control.Monad.Trans.State.Lazy.Extras: exceptState :: Monad m => StateT s (ExceptT e m) a -> ExceptT e (StateT s m) a
- Control.Monad.Trans.State.Lazy.Extras: maybeState :: Monad m => StateT s (MaybeT m) a -> MaybeT (StateT s m) a
- Control.Monad.Trans.State.Strict.Extras: exceptState :: Monad m => StateT s (ExceptT e m) a -> ExceptT e (StateT s m) a
- Control.Monad.Trans.State.Strict.Extras: maybeState :: Monad m => StateT s (MaybeT m) a -> MaybeT (StateT s m) a
+ Control.Also: Als :: f a -> Als f a
+ Control.Also: [getAls] :: Als f a -> f a
+ Control.Also: also :: Also f a => f a -> f a -> f a
+ Control.Also: alsoZero :: Also f a => f a
+ Control.Also: class Also f a
+ Control.Also: instance (Control.Also.Also m a, GHC.Base.Monad m) => Control.Also.Also (Control.Monad.Trans.State.Lazy.StateT s m) a
+ Control.Also: instance (Control.Also.Also m a, GHC.Base.Monad m) => Control.Also.Also (Control.Monad.Trans.State.Strict.StateT s m) a
+ Control.Also: instance (GHC.Base.Monoid a, GHC.Base.Applicative f) => Control.Also.Also f a
+ Control.Also: instance (GHC.Base.Monoid w, Control.Also.Also m a, GHC.Base.Monad m) => Control.Also.Also (Control.Monad.Trans.RWS.Lazy.RWST r w s m) a
+ Control.Also: instance (GHC.Base.Monoid w, Control.Also.Also m a, GHC.Base.Monad m) => Control.Also.Also (Control.Monad.Trans.RWS.Strict.RWST r w s m) a
+ Control.Also: instance (GHC.Base.Monoid w, Control.Also.Also m a, GHC.Base.Monad m) => Control.Also.Also (Control.Monad.Trans.Writer.Lazy.WriterT w m) a
+ Control.Also: instance (GHC.Base.Monoid w, Control.Also.Also m a, GHC.Base.Monad m) => Control.Also.Also (Control.Monad.Trans.Writer.Strict.WriterT w m) a
+ Control.Also: instance Control.Also.Also f a => GHC.Base.Monoid (Control.Also.Als f a)
+ Control.Also: instance Control.Also.Also f a => GHC.Base.Semigroup (Control.Also.Als f a)
+ Control.Also: instance Control.Also.Also m (Data.Either.Either e a) => Control.Also.Also (Control.Monad.Trans.Except.ExceptT e m) a
+ Control.Also: instance Control.Also.Also m (GHC.Base.Maybe a) => Control.Also.Also (Control.Monad.Trans.Maybe.MaybeT m) a
+ Control.Also: instance Control.Also.Also m a => Control.Also.Also (Control.Monad.Trans.Identity.IdentityT m) a
+ Control.Also: instance Control.Also.Also m a => Control.Also.Also (Control.Monad.Trans.Reader.ReaderT r m) a
+ Control.Also: instance Control.Also.Also m r => Control.Also.Also (Control.Monad.Trans.Cont.ContT r m) a
+ Control.Also: instance Control.Newtype.Generics.Newtype (Control.Also.Als f a)
+ Control.Also: instance GHC.Base.Alternative f => GHC.Base.Alternative (Control.Also.Als f)
+ Control.Also: instance GHC.Base.Applicative f => GHC.Base.Applicative (Control.Also.Als f)
+ Control.Also: instance GHC.Base.Functor f => GHC.Base.Functor (Control.Also.Als f)
+ Control.Also: instance GHC.Base.Monad f => GHC.Base.Monad (Control.Also.Als f)
+ Control.Also: instance GHC.Base.MonadPlus f => GHC.Base.MonadPlus (Control.Also.Als f)
+ Control.Also: instance GHC.Base.Monoid a => Control.Also.Also Data.Functor.Identity.Identity a
+ Control.Also: instance GHC.Base.Monoid a => Control.Also.Also GHC.Types.IO a
+ Control.Also: instance GHC.Classes.Eq (f a) => GHC.Classes.Eq (Control.Also.Als f a)
+ Control.Also: instance GHC.Classes.Ord (f a) => GHC.Classes.Ord (Control.Also.Als f a)
+ Control.Also: instance GHC.Enum.Enum (f a) => GHC.Enum.Enum (Control.Also.Als f a)
+ Control.Also: instance GHC.Generics.Generic (Control.Also.Als f a)
+ Control.Also: instance GHC.Generics.Generic1 (Control.Also.Als f)
+ Control.Also: instance GHC.Num.Num (f a) => GHC.Num.Num (Control.Also.Als f a)
+ Control.Also: instance GHC.Read.Read (f a) => GHC.Read.Read (Control.Also.Als f a)
+ Control.Also: instance GHC.Show.Show (f a) => GHC.Show.Show (Control.Also.Als f a)
+ Control.Also: newtype Als f a
+ Control.Monad.Delegate: bind2 :: Monad m => m (Either a b) -> (a -> m r) -> (b -> m r) -> m r
+ Control.Monad.Delegate: bindLeft :: Monad m => m (Either a b) -> (a -> m c) -> m (Either c b)
+ Control.Monad.Delegate: bindRight :: Monad m => m (Either a b) -> (b -> m c) -> m (Either a c)
+ Control.Monad.Delegate: class Monad m => MonadDelegate r m | m -> r
+ Control.Monad.Delegate: delegate :: MonadDelegate r m => ((a -> m r) -> m r) -> m a
+ Control.Monad.Delegate: finish :: forall a r m. MonadDelegate r m => m r -> m a
+ Control.Monad.Delegate: finishLeft :: MonadDelegate r m => m (Either r b) -> m b
+ Control.Monad.Delegate: finishRight :: MonadDelegate r m => m (Either a r) -> m a
+ Control.Monad.Delegate: instance Control.Monad.Delegate.MonadDelegate r m => Control.Monad.Delegate.MonadDelegate r (Control.Monad.Trans.Except.ExceptT e m)
+ Control.Monad.Delegate: instance Control.Monad.Delegate.MonadDelegate r m => Control.Monad.Delegate.MonadDelegate r (Control.Monad.Trans.Identity.IdentityT m)
+ Control.Monad.Delegate: instance Control.Monad.Delegate.MonadDelegate r m => Control.Monad.Delegate.MonadDelegate r (Control.Monad.Trans.Maybe.MaybeT m)
+ Control.Monad.Delegate: instance Control.Monad.Delegate.MonadDelegate r m => Control.Monad.Delegate.MonadDelegate r (Control.Monad.Trans.Reader.ReaderT env m)
+ Control.Monad.Delegate: instance GHC.Base.Monad m => Control.Monad.Delegate.MonadDelegate r (Control.Monad.Trans.Cont.ContT r m)
+ Control.Monad.Delegate: maybeDelegate :: MonadDelegate r m => r -> m (Maybe a) -> m a
+ Control.Monad.Delegate: multitask :: MonadDelegate r m => ((a -> m r) -> (b -> m r) -> m r) -> m (Either a b)
+ Control.Monad.Trans.Maybe.Extras: evalMaybeT :: Functor m => MaybeT m a -> a -> m a
Files
- README.md +9/−1
- alternators.cabal +14/−10
- src/Control/Also.hs +177/−0
- src/Control/Monad/Delegate.hs +92/−0
- src/Control/Monad/Trans/Maybe/Extras.hs +6/−3
- src/Control/Monad/Trans/Reader/Extras.hs +0/−41
- src/Control/Monad/Trans/State/Lazy/Extras.hs +0/−32
- src/Control/Monad/Trans/State/Strict/Extras.hs +0/−32
README.md view
@@ -1,4 +1,12 @@ [](https://hackage.haskell.org/package/alternators) [](http://travis-ci.org/louispan/alternators) -Handy functions when using transformers+`MonadDelegate` assists with coding the handlers for continuation-like monads.++# Changelog++* 1.0.0.0+ - Removed `runReaderM` as it can be replaced with `lift`, `hoist` and `>>=`+ See [gist](https://gist.github.com/louispan/1c7792d45ebe5559ffc45aa9db461c35)+ - Replace `fromMaybeT` with `evalMaybeT`.+ - Added `MonadDelegate` for a more accessing a continuation in the same monad.
alternators.cabal view
@@ -1,7 +1,7 @@ name: alternators-version: 0.1.2.0-synopsis: Handy functions when using transformers-description: Please see README.md+version: 1.0.0.0+synopsis: Handy functions when using transformers.+description: Useful monads built on top of transformers. Please see README.md homepage: https://github.com/louispan/alternators#readme license: BSD3 license-file: LICENSE@@ -12,18 +12,22 @@ build-type: Simple extra-source-files: README.md cabal-version: >=1.10-tested-with: GHC == 7.10.3, GHC == 8.0.1+Tested-With: GHC == 8.4.1 library hs-source-dirs: src- exposed-modules: Control.Monad.Trans.Reader.Extras+ exposed-modules:+ Control.Also+ Control.Monad.Delegate Control.Monad.Trans.Maybe.Extras- Control.Monad.Trans.State.Lazy.Extras- Control.Monad.Trans.State.Strict.Extras build-depends: base >= 4.7 && < 5- , mmorph >= 1 && < 2- , transformers >= 0.4 && < 0.6- ghc-options: -Wall+ , mmorph >= 1+ , mtl >= 2+ , stm >= 2.4+ , newtype-generics >= 0.5+ , transformers >= 0.4+ , lens >= 4+ ghc-options: -Wall -Wredundant-constraints default-language: Haskell2010 source-repository head
+ src/Control/Also.hs view
@@ -0,0 +1,177 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}++module Control.Also where++import Control.Applicative+import Control.Monad+import Control.Monad.Trans.Class+import Control.Monad.Trans.Cont+import Control.Monad.Trans.Except+import Control.Monad.Trans.Identity+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Reader+import Control.Monad.Trans.RWS.Lazy as Lazy+import Control.Monad.Trans.RWS.Strict as Strict+import Control.Monad.Trans.State.Lazy as Lazy+import Control.Monad.Trans.State.Strict as Strict+import Control.Monad.Trans.Writer.Lazy as Lazy+import Control.Monad.Trans.Writer.Strict as Strict+import Control.Newtype.Generics+import Data.Functor.Identity+import GHC.Generics++#if MIN_VERSION_base(4,9,0) && !MIN_VERSION_base(4,10,0)+import Data.Semigroup+#endif++-- | Combining effects where both input effects are used as much as possible.+-- as opposed to 'Control.Applicative.Alternative' where only the "successful" effect is used.+class Also f a where+ -- | An associative binary operation, where both input effects are used as much as possible.+ also :: f a -> f a -> f a+ -- | The identity of 'also'+ alsoZero :: f a++infixr 6 `also` -- like <>++-- | Monoid under 'also'.+-- Mnemonic: 'Als' for 'Also', just like 'Alt' for 'Altenative'+newtype Als f a = Als { getAls :: f a }+ deriving (Generic, Generic1, Read, Show, Eq, Ord, Num, Enum,+ Monad, MonadPlus, Applicative, Alternative, Functor)++instance Newtype (Als f a)++instance Also f a => Semigroup (Als f a) where+ (Als f) <> (Als g) = Als (f `also` g)++instance Also f a => Monoid (Als f a) where+ mempty = Als alsoZero+#if !MIN_VERSION_base(4,11,0)+ (Als f) `mappend` (Als g) = Als (f `also` g)+#endif++-- | Overlappable instance for all Applicatives of Monoids.+#if MIN_VERSION_base(4,11,0)+instance {-# OVERLAPPABLE #-} (Monoid a, Applicative f) => Also f a where+ alsoZero = pure mempty+ f `also` g = liftA2 (<>) f g+#else+instance {-# OVERLAPPABLE #-} (Monoid a, Applicative f) => Also f a where+ alsoZero = pure mempty+ f `also` g = liftA2 mappend f g+#endif++#if MIN_VERSION_base(4,11,0)+instance (Monoid a) => Also Identity a where+ alsoZero = mempty+ a `also` b = a <> b+#else+instance (Monoid a) => Also Identity a where+ alsoZero = mempty+ a `also` b = a `mappend` b+#endif++#if MIN_VERSION_base(4,11,0)+instance (Monoid a) => Also IO a where+ alsoZero = mempty+ a `also` b = a <> b+#else+instance (Monoid a) => Also IO a where+ alsoZero = pure mempty+ a `also` b = liftA2 mappend a b+#endif++instance (Also m a) => Also (IdentityT m) a where+ alsoZero = IdentityT alsoZero+ (IdentityT a) `also` (IdentityT b) = IdentityT $ a `also` b++-- | Combine the monads that returns @r@ not @a@.+instance (Also m r) => Also (ContT r m) a where+ alsoZero = ContT . const $ alsoZero+ (ContT f) `also` (ContT g) =+ ContT $ \k -> (f k) `also` (g k)++instance (Also m a) => Also (ReaderT r m) a where+ alsoZero = ReaderT $ const alsoZero+ (ReaderT f) `also` (ReaderT g) = ReaderT $ \r -> f r `also` g r++instance (Also m (Either e a)) => Also (ExceptT e m) a where+ alsoZero = ExceptT $ alsoZero+ (ExceptT f) `also` (ExceptT g) = ExceptT $ f `also` g++instance (Also m (Maybe a)) => Also (MaybeT m) a where+ alsoZero = MaybeT $ alsoZero+ (MaybeT f) `also` (MaybeT g) = MaybeT $ f `also` g++-- | State instances threads the state through both monad of 'also'+-- in the normal left to right order, and so do not prevent+-- early termination from the left monad (eg if the inner monad was+-- a 'MaybeT' or 'ExceptT'.+-- However, it is able to use the 'also' to combine the return value.+instance (Also m a, Monad m) => Also (Lazy.StateT s m) a where+ alsoZero = lift alsoZero+ f `also` g = do+ (x, y) <- liftA2 (,) f g+ lift $ pure x `also` pure y++-- | State instances threads the state through both monad of 'also'+-- in the normal left to right order, and so do not prevent+-- early termination from the left monad (eg if the inner monad was+-- a 'MaybeT' or 'ExceptT'.+-- However, it is able to use the 'also' to combine the return value.+instance (Also m a, Monad m) => Also (Strict.StateT s m) a where+ alsoZero = lift alsoZero+ f `also` g = do+ (x, y) <- liftA2 (,) f g+ lift $ pure x `also` pure y++-- | Writer instances threads the writer through both monad of 'also'+-- in the normal left to right order, and so do not prevent+-- early termination from the left monad (eg if the inner monad was+-- a 'MaybeT' or 'ExceptT'.+-- However, it is able to use the 'also' to combine the return value.+instance (Monoid w, Also m a, Monad m) => Also (Lazy.WriterT w m) a where+ alsoZero = lift alsoZero+ f `also` g = do+ (x, y) <- liftA2 (,) f g+ lift $ pure x `also` pure y++-- | Writer instances threads the writer through both monad of 'also'+-- in the normal left to right order, and so do not prevent+-- early termination from the left monad (eg if the inner monad was+-- a 'MaybeT' or 'ExceptT'.+-- However, it is able to use the 'also' to combine the return value.+instance (Monoid w, Also m a, Monad m) => Also (Strict.WriterT w m) a where+ alsoZero = lift alsoZero+ f `also` g = do+ (x, y) <- liftA2 (,) f g+ lift $ pure x `also` pure y++-- | State instances threads the state through both monad of 'also'+-- in the normal left to right order, and so do not prevent+-- early termination from the left monad (eg if the inner monad was+-- a 'MaybeT' or 'ExceptT'.+-- However, it is able to use the 'also' to combine the return value.+instance (Monoid w, Also m a, Monad m) => Also (Lazy.RWST r w s m) a where+ alsoZero = lift alsoZero+ f `also` g = do+ (x, y) <- liftA2 (,) f g+ lift $ pure x `also` pure y++-- | State instances threads the state through both monad of 'also'+-- in the normal left to right order, and so do not prevent+-- early termination from the left monad (eg if the inner monad was+-- a 'MaybeT' or 'ExceptT'.+-- However, it is able to use the 'also' to combine the return value.+instance (Monoid w, Also m a, Monad m) => Also (Strict.RWST r w s m) a where+ alsoZero = lift alsoZero+ f `also` g = do+ (x, y) <- liftA2 (,) f g+ lift $ pure x `also` pure y
+ src/Control/Monad/Delegate.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.Delegate where++import Control.Monad.Trans.Class+import Control.Monad.Trans.Cont+import Control.Monad.Trans.Except+import Control.Monad.Trans.Identity+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Reader++class Monad m => MonadDelegate r m | m -> r where+ -- | The inverse of 'delegate' is 'bind'+ --+ -- @+ -- (>>=) :: Monad m => m a -> (a -> m r) -> m r+ -- @+ delegate :: ((a -> m r) -> m r) -> m a++-- | Instance that does real work using continuations+instance Monad m => MonadDelegate r (ContT r m) where+ delegate f = ContT $ \k -> evalContT $ f (lift . k)++-- | Passthrough instance+instance (MonadDelegate r m) => MonadDelegate r (IdentityT m) where+ delegate f = IdentityT $ delegate $ \k -> runIdentityT $ f (lift . k)++-- | Passthrough instance+instance (MonadDelegate r m) => MonadDelegate r (ReaderT env m) where+ delegate f = ReaderT $ \r -> delegate $ \k -> (`runReaderT` r) $ f (lift . k)++-- | Passthrough instance+instance (MonadDelegate r m) => MonadDelegate r (MaybeT m) where+ delegate f = MaybeT . delegate $ \k -> do+ a <- runMaybeT . f $ lift . k . Just+ case a of+ Nothing -> k Nothing+ Just a' -> pure a'++-- | Passthrough instance+instance (MonadDelegate r m) => MonadDelegate r (ExceptT e m) where+ delegate f = ExceptT . delegate $ \kea -> do+ e <- runExceptT . f $ lift . kea . Right -- m (Either e a)+ case e of+ Left e' -> kea (Left e')+ Right r -> pure r++-- | Only handle with given monad, and ignore anything else.+-- This means subseqent fmap, aps, binds are always ignored.+-- @forall@ so @TypeApplications@ can be used to specify the type of @a@+finish :: forall a r m. MonadDelegate r m => m r -> m a+finish = delegate . const++-- | Convert two handler to a monad that may fire two possibilities+-- The inverse is 'bind2'.+multitask :: MonadDelegate r m => ((a -> m r) -> (b -> m r) -> m r) -> m (Either a b)+multitask g = delegate $ \fab -> g (fab . Left) (fab . Right)++-- | Convert a monad that fires two possibilites to a two handlers.+bind2 :: Monad m => m (Either a b) -> (a -> m r) -> (b -> m r) -> m r+bind2 m fa fb = m >>= either fa fb++-- | 'bind' only the 'Right' possibility.+bindRight :: Monad m => m (Either a b) -> (b -> m c) -> m (Either a c)+bindRight m k = bind2 m (pure . Left) (fmap Right . k)++-- | 'bind' only the 'Left' possibility.+bindLeft :: Monad m => m (Either a b) -> (a -> m c) -> m (Either c b)+bindLeft m k = bind2 m (fmap Left . k) (pure . Right)++-- | finish the 'Left' possibility+finishLeft :: MonadDelegate r m => m (Either r b) -> m b+finishLeft m = m >>= either (finish . pure) pure++-- | finish the 'Right' possibility+finishRight :: MonadDelegate r m => m (Either a r) -> m a+finishRight m = m >>= either pure (finish . pure)++-- | maybe 'delegate' the Just value, or just use the @r@.+maybeDelegate :: MonadDelegate r m => r -> m (Maybe a) -> m a+maybeDelegate r m = delegate $ \fire -> do+ ma <- m+ case ma of+ Nothing -> pure r+ Just a -> fire a
src/Control/Monad/Trans/Maybe/Extras.hs view
@@ -1,7 +1,10 @@ module Control.Monad.Trans.Maybe.Extras where -import Control.Applicative import Control.Monad.Trans.Maybe+import Data.Maybe -fromMaybeT :: (Alternative t, Functor m) => MaybeT m a -> m (t a)-fromMaybeT = fmap (maybe empty pure) . runMaybeT+-- | The more useful version is to use 'evalMaybeT' flipped so it can be in a chain of+-- transformer runners, like this @evalCont . (`evalMaybeT` val)@+-- This argument ordering is consistent with 'Control.Monad.Trans.State.evalStateT'.+evalMaybeT :: Functor m => MaybeT m a -> a -> m a+evalMaybeT m a = (fromMaybe a) <$> (runMaybeT m)
− src/Control/Monad/Trans/Reader/Extras.hs
@@ -1,41 +0,0 @@-module Control.Monad.Trans.Reader.Extras where--import Control.Monad.Trans.Reader-import Control.Monad.Morph-import Data.Functor.Identity---- | This function combines two different monadic effects,--- where one of the effects is a reader effect and the other is a--- producing effect.------ This version results in the reader monad's inner effect to be wrapped--- around the producing effect.--- This requires the Reader inner effect to be an MFunctor on Identity.------ This can enable past-Dependence.--- Elm has foldp : (a -> state -> state) -> state -> Signal a -> Signal state--- This is equivalent to a creating a @StateT state (Signal m) ()@------ 'runReaderM' is a more general form of @StateT state (Signal m) ()@ where--- given a reader monad to transform "a" to "c" with effects, and an "as"--- monad that produces "a"s with other effects, run the result of "as" through--- the reader monad to produce "c"s with both effects.--- @--- runReaderM :: Monad m => Reader a (State s) c -> m a -> StateT s m c--- runReaderM :: Reader a (State s) c -> Signal STM a -> StateT state (Signal STM) c--- runReaderM :: Reader a (State s) c -> Pipes.Concurrent.Input a -> StateT state Pipes.Concurrent.Input c--- @-runReaderM :: (Monad m, Monad (t m), MonadTrans t, MFunctor t)- => ReaderT a (t Identity) c -> m a -> t m c-runReaderM c as = do- a <- lift as- hoist generalize $ runReaderT c a---- | An alternate form of runReaderM where the producing effect is--- wrapped around the reader monad's inner effect.--- This requires the producing effect to be an MFunctor on Identity.-runReaderM' :: (Monad m, Monad (t m), MonadTrans t, MFunctor t)- => ReaderT a m c -> (t Identity) a -> t m c-runReaderM' c as = do- a <- hoist generalize as- lift $ runReaderT c a
− src/Control/Monad/Trans/State/Lazy/Extras.hs
@@ -1,32 +0,0 @@-module Control.Monad.Trans.State.Lazy.Extras where--import Control.Monad.Trans.Class-import Control.Monad.Trans.Except-import Control.Monad.Trans.Maybe-import Control.Monad.Trans.State.Lazy---- | The problem with @StateT s (MaybeT m) a@ is that on failure, the original state is lost.--- A more useful type is @MaybeT (StateT s m) a@ which at least keeps the original input state--- on failure.-maybeState :: Monad m => StateT s (MaybeT m) a -> MaybeT (StateT s m) a-maybeState sm = MaybeT $ do- s <- get- r <- lift $ runMaybeT $ runStateT sm s- case r of- Nothing -> pure Nothing- Just (a, s') -> do- put s'- pure (Just a)---- | The problem with @StateT s (ExceptT e m) a@ is that on failure, the original state is lost.--- A more useful type is @ExceptT e (StateT s m) a@ which at least keeps the original input state--- on failure.-exceptState :: Monad m => StateT s (ExceptT e m) a -> ExceptT e (StateT s m) a-exceptState sm = ExceptT $ do- s <- get- r <- lift $ runExceptT $ runStateT sm s- case r of- Left e -> pure $ Left e- Right (a, s') -> do- put s'- pure (Right a)
− src/Control/Monad/Trans/State/Strict/Extras.hs
@@ -1,32 +0,0 @@-module Control.Monad.Trans.State.Strict.Extras where--import Control.Monad.Trans.Class-import Control.Monad.Trans.Except-import Control.Monad.Trans.Maybe-import Control.Monad.Trans.State.Strict---- | The problem with @StateT s (MaybeT m) a@ is that on failure, the original state is lost.--- A more useful type is @MaybeT (StateT s m) a@ which at least keeps the original input state--- on failure.-maybeState :: Monad m => StateT s (MaybeT m) a -> MaybeT (StateT s m) a-maybeState sm = MaybeT $ do- s <- get- r <- lift $ runMaybeT $ runStateT sm s- case r of- Nothing -> pure Nothing- Just (a, s') -> do- put s'- pure (Just a)---- | The problem with @StateT s (ExceptT e m) a@ is that on failure, the original state is lost.--- A more useful type is @ExceptT e (StateT s m) a@ which at least keeps the original input state--- on failure.-exceptState :: Monad m => StateT s (ExceptT e m) a -> ExceptT e (StateT s m) a-exceptState sm = ExceptT $ do- s <- get- r <- lift $ runExceptT $ runStateT sm s- case r of- Left e -> pure $ Left e- Right (a, s') -> do- put s'- pure (Right a)