packages feed

deriving-trans 0.2.0.0 → 0.2.1.0

raw patch · 4 files changed

+126/−45 lines, 4 filesdep −lifted-basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: lifted-base

API changes (from Hackage documentation)

+ Control.Monad.Trans.Elevator: instance Control.Monad.Trans.Class.MonadTrans t => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Elevator.Elevator t)
+ Control.Monad.Trans.Elevator: instance Control.Monad.Trans.Control.MonadTransControl t => Control.Monad.Trans.Control.MonadTransControl (Control.Monad.Trans.Elevator.Elevator t)
- Control.Monad.Trans.Compose: ComposeT :: t1 (t2 m) a -> ComposeT (t1 :: (Type -> Type) -> Type -> Type) (t2 :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type)
+ Control.Monad.Trans.Compose: ComposeT :: t1 (t2 m) a -> ComposeT t1 t2 m a
- Control.Monad.Trans.Compose: [deComposeT] :: ComposeT (t1 :: (Type -> Type) -> Type -> Type) (t2 :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type) -> t1 (t2 m) a
+ Control.Monad.Trans.Compose: [deComposeT] :: ComposeT t1 t2 m a -> t1 (t2 m) a
- Control.Monad.Trans.Compose: newtype ComposeT (t1 :: (Type -> Type) -> Type -> Type) (t2 :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type)
+ Control.Monad.Trans.Compose: newtype ComposeT t1 t2 m a
- Control.Monad.Trans.Elevator: Ascend :: t m a -> Elevator (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type)
+ Control.Monad.Trans.Elevator: Ascend :: t m a -> Elevator t m a
- Control.Monad.Trans.Elevator: [descend] :: Elevator (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type) -> t m a
+ Control.Monad.Trans.Elevator: [descend] :: Elevator t m a -> t m a
- Control.Monad.Trans.Elevator: newtype Elevator (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type)
+ Control.Monad.Trans.Elevator: newtype Elevator t m a

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for deriving-trans +## 0.2.1.0 *27 Jan 2022*++* Use StandaloneKindSignatures.+* Add Haddock documentation.+ ## 0.2.0.0 *25 Jan 2022*  * Completely change the idea of this project. Pretty much everything has been changed.
deriving-trans.cabal view
@@ -1,12 +1,17 @@ cabal-version:       3.0 name:                deriving-trans-version:             0.2.0.0-synopsis:            Derive monad type classes with DerivingVia-description:         Deriving type class instances for monad transformer stacks can be tedious.-                     By actually composing transformers with `ComposeT` we don't need to implement-                     each type class for each transformer.-                     Instead we need a single instance for `Elevator`, which will then help us pick-                     the correct instance with DerivingVia.+version:             0.2.1.0+synopsis:            Derive instances for monad transformer stacks+description:         Implementing instances for monad transformer stacks can be tedious.+                     <https://hackage.haskell.org/package/mtl mtl> defines each instance for each transfomer.++                     'Elevator' let's you access instances of the underlying monad of a transformer.+                     Composing transformers with 'ComposeT' brings instances into scope during the+                     initialization of a transformer stack.++                     'Elevator' can be used with DerivingVia to select a specific transformer to+                     derive instances for a transformer stack.+                     'ComposeT' composes transformers and accumulates instances in a transformer stack. license:             BSD-3-Clause license-file:        LICENSE author:              Felix Springer@@ -24,7 +29,6 @@   --other-modules:   build-depends:     , base              >= 4.5     && < 5-    , lifted-base       >= 0.2.3.2 && < 0.2.4     , monad-control     >= 1.0.2.0 && < 1.1     , mtl               >= 2.2.2   && < 2.3     , transformers      >= 0.5.6.2 && < 0.5.7@@ -51,6 +55,7 @@     OverloadedStrings     RankNTypes     StandaloneDeriving+    StandaloneKindSignatures     TypeApplications     TypeFamilies   ghc-options: -Wall
src/Control/Monad/Trans/Compose.hs view
@@ -13,12 +13,16 @@ import Control.Monad.Writer.Class import Data.Kind -newtype ComposeT-  (t1 :: (Type -> Type) -> Type -> Type)-  (t2 :: (Type -> Type) -> Type -> Type)-  (m :: Type -> Type)-  (a :: Type)-    = ComposeT { deComposeT :: t1 (t2 m) a }+-- | A newtype wrapper for two stacked monad transformers.+--+-- Access instances of the intermediate monad @('t2' 'm')@, whenever 't1' implements+-- 'MonadTrans'/'MonadTransControl'.+type ComposeT :: ((Type -> Type) -> Type -> Type) -- ^ 't1'+              -> ((Type -> Type) -> Type -> Type) -- ^ 't2'+              -> (Type -> Type) -- ^ 'm'+              -> Type -- ^ 'a'+              -> Type+newtype ComposeT t1 t2 m a = ComposeT { deComposeT :: t1 (t2 m) a }   deriving newtype (Applicative, Functor, Monad)  instance (forall m. Monad m => Monad (t2 m), MonadTrans t1, MonadTrans t2) => MonadTrans (ComposeT t1 t2) where@@ -29,7 +33,7 @@   liftWith f = defaultLiftWith2 ComposeT deComposeT $ \ x -> f x   restoreT = defaultRestoreT2 ComposeT --- | Elevated to `m`.+-- | Elevated to 'm'. deriving via Elevator (ComposeT t1 t2) m   instance     ( Monad (t1 (t2 m))@@ -37,7 +41,7 @@     , MonadIO m     ) => MonadIO (ComposeT t1 t2 m) --- | Elevated to `m`.+-- | Elevated to 'm'. deriving via Elevator (ComposeT t1 t2) m   instance     ( Monad (t1 (t2 m))@@ -45,7 +49,7 @@     , MonadBase b m     ) => MonadBase b (ComposeT t1 t2 m) --- | Elevated to `m`.+-- | Elevated to 'm'. deriving via Elevator (ComposeT t1 t2) m   instance     ( Monad (t1 (t2 m))@@ -53,7 +57,7 @@     , MonadBaseControl b m     ) => MonadBaseControl b (ComposeT t1 t2 m) --- | Elevated to `t2 m`.+-- | Elevated to @('t2' 'm')@. deriving via Elevator t1 (t2 (m :: * -> *))   instance     ( Monad (t1 (t2 m))@@ -61,7 +65,7 @@     , MonadError e (t2 m)     ) => MonadError e (ComposeT t1 t2 m) --- | Elevated to `t2 m`.+-- | Elevated to @('t2' 'm')@. deriving via Elevator t1 (t2 (m :: * -> *))   instance     ( Monad (t1 (t2 m))@@ -69,7 +73,7 @@     , MonadReader r (t2 m)     ) => MonadReader r (ComposeT t1 t2 m) --- | Elevated to `t2 m`.+-- | Elevated to @('t2' 'm')@. deriving via Elevator t1 (t2 (m :: * -> *))   instance     ( Monad (t1 (t2 m))@@ -77,7 +81,7 @@     , MonadState s (t2 m)     ) => MonadState s (ComposeT t1 t2 m) --- | Elevated to `t2 m`.+-- | Elevated to @('t2' 'm')@. deriving via Elevator t1 (t2 (m :: * -> *))   instance     ( Monad (t1 (t2 m))@@ -85,12 +89,23 @@     , MonadWriter w (t2 m)     ) => MonadWriter w (ComposeT t1 t2 m) -runComposeT :: (forall a. t1 (t2 m) a -> t2 m (StT t1 a))-            -> (forall a. t2 m a -> m (StT t2 a))+-- | Run a transformer stack.+--+-- This function takes the two individual monad transformer runners as arguments.+runComposeT :: (forall a. t1 (t2 m) a -> t2 m (StT t1 a)) -- ^ run 't1'+            -> (forall a. t2 m a -> m (StT t2 a)) -- ^ run 't2'             -> (forall a. ComposeT t1 t2 m a -> m (StT t2 (StT t1 a))) runComposeT runT1 runT2 = runT2 . runT1 . deComposeT -runComposeT' :: (t1 (t2 m) a -> t2 m a)-             -> (t2 m a -> m a)+-- | Equivalent to 'runComposeT', but discards the monadic state 'StT'.+-- This is a simple approach when your monad transformer stack doesn't carry monadic state.+--+-- @+-- 'StT' ('ComposeT' 't1' 't2') a ~ a+-- @+--+-- This can be used to improve error messages when modifying a monad transformer stack.+runComposeT' :: (t1 (t2 m) a -> t2 m a) -- ^ run 't1'+             -> (t2 m a -> m a) -- ^ run 't2'              -> (ComposeT t1 t2 m a -> m a) runComposeT' runT1 runT2 = runT2 . runT1 . deComposeT
src/Control/Monad/Trans/Elevator.hs view
@@ -11,40 +11,96 @@ import Control.Monad.Writer.Class import Data.Kind -newtype Elevator-  (t :: (Type -> Type) -> Type -> Type)-  (m :: Type -> Type)-  (a :: Type)-    = Ascend { descend :: t m a }+-- | A newtype wrapper for monad transformers.+--+-- Access instances of the inner monad 'm'.+type Elevator :: ((Type -> Type) -> Type -> Type) -- ^ 't'+              -> (Type -> Type) -- ^ 'm'+              -> Type -- ^ 'a'+              -> Type+newtype Elevator t m a = Ascend { descend :: t m a }   deriving newtype (Applicative, Functor, Monad)+  deriving newtype (MonadTrans, MonadTransControl)  instance (Monad (t m), MonadTrans t, MonadBase b m) => MonadBase b (Elevator t m) where-  liftBase = Ascend . lift . liftBase+  liftBase = lift . liftBase  instance (Monad (t m), MonadTransControl t, MonadBaseControl b m) => MonadBaseControl b (Elevator t m) where   type StM (Elevator t m) a = StM m (StT t a)-  liftBaseWith f = Ascend $ liftWith $ \ runT -> liftBaseWith $ \ runInBase -> f $ runInBase . runT . descend-  restoreM = Ascend . restoreT . restoreM+  liftBaseWith f = liftWith $ \ runT -> liftBaseWith $ \ runInBase -> f $ runInBase . runT+  restoreM = restoreT . restoreM  instance (Monad (t m), MonadTrans t, MonadIO m) => MonadIO (Elevator t m) where-  liftIO = Ascend . lift . liftIO+  liftIO = lift . liftIO  instance (Monad (t m), MonadTransControl t, MonadError e m) => MonadError e (Elevator t m) where-  throwError = Ascend . lift . throwError-  catchError throwing catching = Ascend $ (restoreT . pure =<<) $ liftWith $ \ runT ->-    catchError (runT $ descend throwing) (runT . descend . catching)+  throwError = lift . throwError+  catchError throwing catching = (restoreT . pure =<<) $ liftWith $ \ runT ->+    catchError (runT throwing) (runT . catching)  instance (Monad (t m), MonadTransControl t, MonadReader r m) => MonadReader r (Elevator t m) where-  ask = Ascend $ lift ask-  local f tma = Ascend $ (restoreT . pure =<<) $ liftWith $ \ runT ->-    local f $ runT $ descend tma+  ask = lift ask+  local f tma = (restoreT . pure =<<) $ liftWith $ \ runT ->+    local f $ runT tma  instance (Monad (t m), MonadTrans t, MonadState s m) => MonadState s (Elevator t m) where-  get = Ascend $ lift get-  put = Ascend . lift . put+  get = lift get+  put = lift . put  instance (Monad (t m), MonadTransControl t, MonadWriter w m) => MonadWriter w (Elevator t m) where-  tell = Ascend . lift . tell-  listen tma = Ascend $ liftWith (\ runT -> listen $ runT $ descend tma) >>= \ (sta, w) ->+  tell = lift . tell+  listen tma = liftWith (\ runT -> listen $ runT tma) >>= \ (sta, w) ->     (, w) <$> restoreT (pure sta)-  pass tma = Ascend $ lift . pass . pure =<< descend tma+  pass tma = lift . pass . pure =<< tma++-- * Examples+--+-- $examples+--+-- == Example 1: Recover submerged instances+--+-- Let's assume you want to define a monad transformer stack.+--+-- @+-- newtype StackT m a = StackT { unStackT :: ReaderT Char (ReaderT Bool m) a }+--   deriving newtype (Functor, Applicative Monad)+-- @+--+-- Now you want to expose the inner @(MonadReader Bool)@ instance with @(StackT m)@.+--+-- Normally it's shadowed by the @(MonadReader Char)@ instance, but we can use @Elevator@ to access+-- the inner transformer.+--+-- @+--   deriving (MonadReader Bool) via (Elevator (ReaderT Char) (ReaderT Bool m))+-- @+--+-- == Example 2: Custom transformer without boilerplate+--+-- Let's assume you have defined a monad transformer.+--+-- @+-- newtype CustomT m a = CustomT { unComposeT :: IdentityT m a }+--   deriving newtype (Functor, Applicative Monad)+--   deriving newtype (MonadTrans, MonadTransControl)+--+-- runCustomT :: CustomT m a -> m a+-- runCustomT = runIdentityT . unComposeT+-- @+--+-- Now you want to use this monad transformer in a transformer stack.+--+-- @+-- newtype StackT m a = { unStackT :: CustomT (ReaderT Bool m) a }+--   deriving newtype (Functor, Applicative Monad)+--   deriving newtype (MonadTrans, MonadTransControl)+-- @+--+-- Unfortunately we can't derive a @Monad m => MonadReader Bool (StackT m)@ instance with+-- GeneralizedNewtypeDeriving, without also adding the instance to @CustomT@.+--+-- To still derive this trivial instance we can use @Elevator@ with DerivingVia.+--+-- @+--   deriving (MonadReader Bool) via (Elevator CustomT (ReaderT Bool m))+-- @