From 4f3d5d802b0e3f492f23a94c0d79532659bc4e89 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Wed, 17 Apr 2024 15:39:10 -0400 Subject: [PATCH 01/12] initial concept of Bypass for deriving via --- Control/Monad/Bypass.hs | 40 ++++++++++++++++++++++++++++++++++++++++ mtl.cabal | 1 + 2 files changed, 41 insertions(+) create mode 100644 Control/Monad/Bypass.hs diff --git a/Control/Monad/Bypass.hs b/Control/Monad/Bypass.hs new file mode 100644 index 0000000..7c8862e --- /dev/null +++ b/Control/Monad/Bypass.hs @@ -0,0 +1,40 @@ +{-# LANGUAGE StandaloneKindSignatures #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} + +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE DerivingVia #-} +module Control.Monad.Bypass + ( Bypass + ) where + +import Control.Monad.Reader +import Control.Monad.State +import Control.Monad.Writer +import Data.Kind (Type) + +type Bypass :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type +newtype Bypass t m a = Bypass (t m a) deriving (Functor, Applicative, Monad, MonadTrans) + +instance MonadReader r m => MonadReader r (Bypass (ReaderT r') m) where + ask = lift ask + local f (Bypass (ReaderT x)) = Bypass . ReaderT $ local f . x + reader = lift . reader + +instance (MonadWriter w m, Monoid w') => MonadWriter w (Bypass (WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen (Bypass (WriterT x)) = Bypass $ WriterT $ (\((a, w'), w) -> ((a, w), w')) <$> listen x + pass (Bypass (WriterT x)) = Bypass $ WriterT $ (\((a,f),w') -> pass $ return ((a,w'),f)) =<< x + +instance MonadState s m => MonadState s (Bypass (StateT s') m) where + get = lift get + put = lift . put + state = lift . state + +newtype ExampleT m a = ExampleT (ReaderT Int m a) deriving (Functor, Applicative, Monad) + +deriving via Bypass (ReaderT Int) m instance MonadReader r m => MonadReader r (ExampleT m) + diff --git a/mtl.cabal b/mtl.cabal index 6174624..77eda4c 100644 --- a/mtl.cabal +++ b/mtl.cabal @@ -32,6 +32,7 @@ Library exposed-modules: Control.Monad.Cont Control.Monad.Cont.Class + Control.Monad.Bypass Control.Monad.Error.Class Control.Monad.Except Control.Monad.Identity From cad092ea90085d4ed2ae522c74bcbe36e1a2b40e Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Thu, 18 Apr 2024 10:55:31 -0400 Subject: [PATCH 02/12] switched to Lifting* convention --- Control/Monad/Bypass.hs | 40 ----------------------------------- Control/Monad/Reader.hs | 2 ++ Control/Monad/Reader/Class.hs | 22 +++++++++++++++++-- mtl.cabal | 1 - 4 files changed, 22 insertions(+), 43 deletions(-) delete mode 100644 Control/Monad/Bypass.hs diff --git a/Control/Monad/Bypass.hs b/Control/Monad/Bypass.hs deleted file mode 100644 index 7c8862e..0000000 --- a/Control/Monad/Bypass.hs +++ /dev/null @@ -1,40 +0,0 @@ -{-# LANGUAGE StandaloneKindSignatures #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} - -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE DerivingVia #-} -module Control.Monad.Bypass - ( Bypass - ) where - -import Control.Monad.Reader -import Control.Monad.State -import Control.Monad.Writer -import Data.Kind (Type) - -type Bypass :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type -newtype Bypass t m a = Bypass (t m a) deriving (Functor, Applicative, Monad, MonadTrans) - -instance MonadReader r m => MonadReader r (Bypass (ReaderT r') m) where - ask = lift ask - local f (Bypass (ReaderT x)) = Bypass . ReaderT $ local f . x - reader = lift . reader - -instance (MonadWriter w m, Monoid w') => MonadWriter w (Bypass (WriterT w') m) where - writer = lift . writer - tell = lift . tell - listen (Bypass (WriterT x)) = Bypass $ WriterT $ (\((a, w'), w) -> ((a, w), w')) <$> listen x - pass (Bypass (WriterT x)) = Bypass $ WriterT $ (\((a,f),w') -> pass $ return ((a,w'),f)) =<< x - -instance MonadState s m => MonadState s (Bypass (StateT s') m) where - get = lift get - put = lift . put - state = lift . state - -newtype ExampleT m a = ExampleT (ReaderT Int m a) deriving (Functor, Applicative, Monad) - -deriving via Bypass (ReaderT Int) m instance MonadReader r m => MonadReader r (ExampleT m) - diff --git a/Control/Monad/Reader.hs b/Control/Monad/Reader.hs index 4f2f649..ba98d53 100644 --- a/Control/Monad/Reader.hs +++ b/Control/Monad/Reader.hs @@ -40,6 +40,8 @@ module Control.Monad.Reader ( -- * MonadReader class MonadReader.MonadReader(..), MonadReader.asks, + -- * Lifting helper type + MonadReader.LiftingReader, -- * The Reader monad Reader, runReader, diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index 6cb83dd..cc30a4a 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -1,9 +1,11 @@ -{-# LANGUAGE Safe #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} -- Search for UndecidableInstances to see why this is needed {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE StandaloneKindSignatures #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE Trustworthy #-} -- Needed because the CPSed versions of Writer and State are secretly State -- wrappers, which don't force such constraints, even though they should legally -- be there. @@ -48,6 +50,7 @@ than using the 'Control.Monad.State.State' monad. module Control.Monad.Reader.Class ( MonadReader(..), asks, + LiftingReader(..), ) where import qualified Control.Monad.Trans.Cont as Cont @@ -68,7 +71,8 @@ import qualified Control.Monad.Trans.Accum as Accum import Control.Monad.Trans.Select (SelectT (SelectT), runSelectT) import qualified Control.Monad.Trans.RWS.CPS as CPSRWS import qualified Control.Monad.Trans.Writer.CPS as CPS -import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Class (MonadTrans(lift)) +import Data.Kind (Type) -- ---------------------------------------------------------------------------- -- class MonadReader @@ -202,3 +206,17 @@ instance r <- ask local f (runSelectT m (local (const r) . c)) reader = lift . reader + +type LiftingReader :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type +newtype LiftingReader t m a = LiftingReader (t m a) + deriving (Functor, Applicative, Monad, MonadTrans) + +instance MonadReader r m => MonadReader r (LiftingReader (ReaderT r') m) where + ask = lift ask + local f (LiftingReader (ReaderT.ReaderT x)) = LiftingReader . ReaderT.ReaderT $ local f . x + reader = lift . reader + +instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (LazyRWS.RWST r' w s) m) where + ask = lift ask + local f (LiftingReader (LazyRWS.RWST x)) = LiftingReader . LazyRWS.RWST $ \r s -> local f $ x r s + reader = lift . reader diff --git a/mtl.cabal b/mtl.cabal index 77eda4c..6174624 100644 --- a/mtl.cabal +++ b/mtl.cabal @@ -32,7 +32,6 @@ Library exposed-modules: Control.Monad.Cont Control.Monad.Cont.Class - Control.Monad.Bypass Control.Monad.Error.Class Control.Monad.Except Control.Monad.Identity From f92ef908a8c4eec75abc56f8243c35e0482c5ff2 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 5 May 2024 14:40:43 -0400 Subject: [PATCH 03/12] added LiftingReader LiftingWriter LiftingState --- Control/Monad/Reader/Class.hs | 29 ++++++++--- Control/Monad/State/Class.hs | 44 +++++++++++++++-- Control/Monad/Writer/CPS.hs | 2 + Control/Monad/Writer/Class.hs | 88 +++++++++++++++++++++++++++++++++- Control/Monad/Writer/Lazy.hs | 2 + Control/Monad/Writer/Strict.hs | 2 + 6 files changed, 155 insertions(+), 12 deletions(-) diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index cc30a4a..4eed77f 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -1,14 +1,15 @@ +{-# LANGUAGE Trustworthy #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} -- Search for UndecidableInstances to see why this is needed {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE StandaloneKindSignatures #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE Trustworthy #-} -- Needed because the CPSed versions of Writer and State are secretly State -- wrappers, which don't force such constraints, even though they should legally -- be there. +{-# LANGUAGE StandaloneKindSignatures #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-redundant-constraints #-} {- | Module : Control.Monad.Reader.Class @@ -207,16 +208,30 @@ instance local f (runSelectT m (local (const r) . c)) reader = lift . reader +-- | A helper type to decrease boilerplate when defining new transformer +-- instances of 'MonadReader'. +-- +-- @since ???? type LiftingReader :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type newtype LiftingReader t m a = LiftingReader (t m a) deriving (Functor, Applicative, Monad, MonadTrans) -instance MonadReader r m => MonadReader r (LiftingReader (ReaderT r') m) where +instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (LazyRWS.RWST r' w s) m) where ask = lift ask - local f (LiftingReader (ReaderT.ReaderT x)) = LiftingReader . ReaderT.ReaderT $ local f . x + local f (LiftingReader (LazyRWS.RWST x)) = LiftingReader . LazyRWS.RWST $ \r s -> local f $ x r s reader = lift . reader -instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (LazyRWS.RWST r' w s) m) where +instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (StrictRWS.RWST r' w s) m) where ask = lift ask - local f (LiftingReader (LazyRWS.RWST x)) = LiftingReader . LazyRWS.RWST $ \r s -> local f $ x r s + local f (LiftingReader (StrictRWS.RWST x)) = LiftingReader . StrictRWS.RWST $ \r s -> local f $ x r s + reader = lift . reader + +instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (CPSRWS.RWST r' w s) m) where + ask = lift ask + local f (LiftingReader (CPSRWS.runRWST -> x)) = LiftingReader . CPSRWS.rwsT $ \r s -> local f $ x r s + reader = lift . reader + +instance MonadReader r m => MonadReader r (LiftingReader (ReaderT r') m) where + ask = lift ask + local f (LiftingReader (ReaderT.ReaderT x)) = LiftingReader . ReaderT.ReaderT $ local f . x reader = lift . reader diff --git a/Control/Monad/State/Class.hs b/Control/Monad/State/Class.hs index df5a33d..b84d4ef 100644 --- a/Control/Monad/State/Class.hs +++ b/Control/Monad/State/Class.hs @@ -1,4 +1,6 @@ -{-# LANGUAGE Safe #-} +{-# LANGUAGE Trustworthy #-} +{-# LANGUAGE StandaloneKindSignatures #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -33,7 +35,8 @@ module Control.Monad.State.Class ( MonadState(..), modify, modify', - gets + gets, + LiftingState ) where import Control.Monad.Trans.Cont (ContT) @@ -51,7 +54,8 @@ import Control.Monad.Trans.Accum (AccumT) import Control.Monad.Trans.Select (SelectT) import qualified Control.Monad.Trans.RWS.CPS as CPSRWS import qualified Control.Monad.Trans.Writer.CPS as CPS -import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Class (MonadTrans(lift)) +import Data.Kind (Type) -- --------------------------------------------------------------------------- @@ -192,3 +196,37 @@ instance MonadState s m => MonadState s (SelectT r m) where get = lift get put = lift . put state = lift . state + +-- | A helper type to decrease boilerplate when defining new transformer +-- instances of 'MonadState'. +-- +-- @since ???? +type LiftingState :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type +newtype LiftingState t m a = LiftingState (t m a) + deriving (Functor, Applicative, Monad, MonadTrans) + +instance (MonadState s m, Monoid w) => MonadState s (LiftingState (LazyRWS.RWST r w s') m) where + get = lift get + put = lift . put + state = lift . state + +instance (MonadState s m, Monoid w) => MonadState s (LiftingState (StrictRWS.RWST r w s') m) where + get = lift get + put = lift . put + state = lift . state + +instance (MonadState s m, Monoid w) => MonadState s (LiftingState (CPSRWS.RWST r w s') m) where + get = lift get + put = lift . put + state = lift . state + +instance MonadState s m => MonadState s (LiftingState (Lazy.StateT s') m) where + get = lift get + put = lift . put + state = lift . state + +instance MonadState s m => MonadState s (LiftingState (Strict.StateT s') m) where + get = lift get + put = lift . put + state = lift . state + diff --git a/Control/Monad/Writer/CPS.hs b/Control/Monad/Writer/CPS.hs index ad9d34d..4ecd36c 100644 --- a/Control/Monad/Writer/CPS.hs +++ b/Control/Monad/Writer/CPS.hs @@ -26,6 +26,8 @@ module Control.Monad.Writer.CPS ( MonadWriter.MonadWriter(..), MonadWriter.listens, MonadWriter.censor, + -- * Lifting helper type + MonadWriter.LiftingWriter, -- * The Writer monad Writer, runWriter, diff --git a/Control/Monad/Writer/Class.hs b/Control/Monad/Writer/Class.hs index 11c156a..aa7ce4b 100644 --- a/Control/Monad/Writer/Class.hs +++ b/Control/Monad/Writer/Class.hs @@ -1,8 +1,13 @@ -{-# LANGUAGE Safe #-} +{-# LANGUAGE Trustworthy #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE StandaloneKindSignatures #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE ViewPatterns #-} +{-# OPTIONS_GHC -Wno-name-shadowing #-} -- Search for UndecidableInstances to see why this is needed ----------------------------------------------------------------------------- @@ -28,6 +33,7 @@ module Control.Monad.Writer.Class ( MonadWriter(..), listens, censor, + LiftingWriter(..), ) where import Control.Monad.Trans.Except (ExceptT) @@ -47,7 +53,8 @@ import Control.Monad.Trans.Accum (AccumT) import qualified Control.Monad.Trans.Accum as Accum import qualified Control.Monad.Trans.RWS.CPS as CPSRWS import qualified Control.Monad.Trans.Writer.CPS as CPS -import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Class (MonadTrans(lift)) +import Data.Kind (Type) -- --------------------------------------------------------------------------- -- MonadWriter class @@ -205,3 +212,80 @@ instance tell = lift . tell listen = Accum.liftListen listen pass = Accum.liftPass pass + + +-- | A helper type to decrease boilerplate when defining new transformer +-- instances of 'MonadWriter'. +-- +-- @since ???? +type LiftingWriter :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type +newtype LiftingWriter t m a = LiftingWriter {runLiftingWriter :: t m a} + deriving (Functor, Applicative, Monad, MonadTrans) + + +instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) where + writer = lift . writer + tell = lift . tell + listen (LiftingWriter (LazyRWS.RWST x)) = LiftingWriter $ LazyRWS.RWST $ \r s -> do + ((a, s, w'), w) <- listen $ x r s + pure ((a, w), s, w') + pass (LiftingWriter (LazyRWS.RWST x)) = LiftingWriter $ LazyRWS.RWST $ \r s -> do + (y, s, w') <- x r s + a <- pass $ pure y + pure (a, s, w') + +instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) where + writer = lift . writer + tell = lift . tell + listen (LiftingWriter (StrictRWS.RWST x)) = LiftingWriter $ StrictRWS.RWST $ \r s -> do + ((a, s, w'), w) <- listen $ x r s + pure ((a, w), s, w') + pass (LiftingWriter (StrictRWS.RWST x)) = LiftingWriter $ StrictRWS.RWST $ \r s -> do + (y, s, w') <- x r s + a <- pass $ pure y + pure (a, s, w') + +instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) where + writer = lift . writer + tell = lift . tell + listen (LiftingWriter (CPSRWS.runRWST -> x)) = LiftingWriter $ CPSRWS.rwsT $ \r s -> do + ((a, s, w'), w) <- listen $ x r s + pure ((a, w), s, w') + pass (LiftingWriter (CPSRWS.runRWST -> x)) = LiftingWriter $ CPSRWS.rwsT $ \r s -> do + (y, s, w') <- x r s + a <- pass $ pure y + pure (a, s, w') + +instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (Lazy.WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen (LiftingWriter (Lazy.WriterT x)) = LiftingWriter $ Lazy.WriterT $ do + ((a, w'), w) <- listen x + pure ((a, w), w') + pass (LiftingWriter (Lazy.WriterT x)) = LiftingWriter $ Lazy.WriterT $ do + (y, w') <- x + a <- pass $ pure y + pure (a, w') + +instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (Strict.WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen (LiftingWriter (Strict.WriterT x)) = LiftingWriter $ Strict.WriterT $ do + ((a, w'), w) <- listen x + pure ((a, w), w') + pass (LiftingWriter (Strict.WriterT x)) = LiftingWriter $ Strict.WriterT $ do + (y, w') <- x + a <- pass $ pure y + pure (a, w') + +instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (CPS.WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen (LiftingWriter (CPS.runWriterT -> x)) = LiftingWriter $ CPS.writerT $ do + ((a, w'), w) <- listen x + pure ((a, w), w') + pass (LiftingWriter (CPS.runWriterT -> x)) = LiftingWriter $ CPS.writerT $ do + (y, w') <- x + a <- pass $ pure y + pure (a, w') + diff --git a/Control/Monad/Writer/Lazy.hs b/Control/Monad/Writer/Lazy.hs index 6013f0c..d4b7bf9 100644 --- a/Control/Monad/Writer/Lazy.hs +++ b/Control/Monad/Writer/Lazy.hs @@ -23,6 +23,8 @@ module Control.Monad.Writer.Lazy ( MonadWriter.MonadWriter(..), MonadWriter.listens, MonadWriter.censor, + -- * Lifting helper type + MonadWriter.LiftingWriter, -- * The Writer monad Writer, runWriter, diff --git a/Control/Monad/Writer/Strict.hs b/Control/Monad/Writer/Strict.hs index 0844753..2cedb95 100644 --- a/Control/Monad/Writer/Strict.hs +++ b/Control/Monad/Writer/Strict.hs @@ -23,6 +23,8 @@ module Control.Monad.Writer.Strict ( MonadWriter.MonadWriter(..), MonadWriter.listens, MonadWriter.censor, + -- * Lifting helper type + MonadWriter.LiftingWriter, -- * The Writer monad Writer, runWriter, From 9e325fd5018ebe40540711e665c80d0e29b9666e Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Tue, 7 May 2024 08:35:12 -0400 Subject: [PATCH 04/12] MonadTrans for LiftingState instance --- Control/Monad/State/Class.hs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/Control/Monad/State/Class.hs b/Control/Monad/State/Class.hs index b84d4ef..c523be4 100644 --- a/Control/Monad/State/Class.hs +++ b/Control/Monad/State/Class.hs @@ -205,27 +205,7 @@ type LiftingState :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type newtype LiftingState t m a = LiftingState (t m a) deriving (Functor, Applicative, Monad, MonadTrans) -instance (MonadState s m, Monoid w) => MonadState s (LiftingState (LazyRWS.RWST r w s') m) where - get = lift get - put = lift . put - state = lift . state - -instance (MonadState s m, Monoid w) => MonadState s (LiftingState (StrictRWS.RWST r w s') m) where - get = lift get - put = lift . put - state = lift . state - -instance (MonadState s m, Monoid w) => MonadState s (LiftingState (CPSRWS.RWST r w s') m) where - get = lift get - put = lift . put - state = lift . state - -instance MonadState s m => MonadState s (LiftingState (Lazy.StateT s') m) where - get = lift get - put = lift . put - state = lift . state - -instance MonadState s m => MonadState s (LiftingState (Strict.StateT s') m) where +instance (MonadState s m, MonadTrans t, Monad (t m)) => MonadState s (LiftingState t m) where get = lift get put = lift . put state = lift . state From 570366d6e80095552a22c310e4f745e93cf631b5 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Tue, 7 May 2024 12:56:54 -0400 Subject: [PATCH 05/12] ghci panic --- Control/Monad/Writer/Class.hs | 137 ++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/Control/Monad/Writer/Class.hs b/Control/Monad/Writer/Class.hs index aa7ce4b..0fa78b0 100644 --- a/Control/Monad/Writer/Class.hs +++ b/Control/Monad/Writer/Class.hs @@ -1,12 +1,14 @@ {-# LANGUAGE Trustworthy #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE StandaloneKindSignatures #-} +{-# LANGUAGE KindSignatures #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE DerivingVia #-} {-# OPTIONS_GHC -Wno-name-shadowing #-} -- Search for UndecidableInstances to see why this is needed @@ -222,70 +224,75 @@ type LiftingWriter :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type newtype LiftingWriter t m a = LiftingWriter {runLiftingWriter :: t m a} deriving (Functor, Applicative, Monad, MonadTrans) +type LiftingWriterInternal :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type +newtype LiftingWriterInternal t m a = LiftingWriterInternal {runLiftingWriterInternal :: t m a} + deriving (Functor, Applicative, Monad, MonadTrans) -instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) where - writer = lift . writer - tell = lift . tell - listen (LiftingWriter (LazyRWS.RWST x)) = LiftingWriter $ LazyRWS.RWST $ \r s -> do - ((a, s, w'), w) <- listen $ x r s - pure ((a, w), s, w') - pass (LiftingWriter (LazyRWS.RWST x)) = LiftingWriter $ LazyRWS.RWST $ \r s -> do - (y, s, w') <- x r s - a <- pass $ pure y - pure (a, s, w') - -instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) where - writer = lift . writer - tell = lift . tell - listen (LiftingWriter (StrictRWS.RWST x)) = LiftingWriter $ StrictRWS.RWST $ \r s -> do - ((a, s, w'), w) <- listen $ x r s - pure ((a, w), s, w') - pass (LiftingWriter (StrictRWS.RWST x)) = LiftingWriter $ StrictRWS.RWST $ \r s -> do - (y, s, w') <- x r s - a <- pass $ pure y - pure (a, s, w') - -instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) where - writer = lift . writer - tell = lift . tell - listen (LiftingWriter (CPSRWS.runRWST -> x)) = LiftingWriter $ CPSRWS.rwsT $ \r s -> do - ((a, s, w'), w) <- listen $ x r s - pure ((a, w), s, w') - pass (LiftingWriter (CPSRWS.runRWST -> x)) = LiftingWriter $ CPSRWS.rwsT $ \r s -> do - (y, s, w') <- x r s - a <- pass $ pure y - pure (a, s, w') - -instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (Lazy.WriterT w') m) where +instance (MonadWriter w m, MonadTrans (t w'), Monad (t w' m), Monoid w', MapLiftingWriter s t) => MonadWriter w (LiftingWriterInternal (t w') m) where writer = lift . writer tell = lift . tell - listen (LiftingWriter (Lazy.WriterT x)) = LiftingWriter $ Lazy.WriterT $ do - ((a, w'), w) <- listen x - pure ((a, w), w') - pass (LiftingWriter (Lazy.WriterT x)) = LiftingWriter $ Lazy.WriterT $ do - (y, w') <- x - a <- pass $ pure y - pure (a, w') - -instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (Strict.WriterT w') m) where - writer = lift . writer - tell = lift . tell - listen (LiftingWriter (Strict.WriterT x)) = LiftingWriter $ Strict.WriterT $ do - ((a, w'), w) <- listen x - pure ((a, w), w') - pass (LiftingWriter (Strict.WriterT x)) = LiftingWriter $ Strict.WriterT $ do - (y, w') <- x - a <- pass $ pure y - pure (a, w') - -instance (Monoid w', MonadWriter w m) => MonadWriter w (LiftingWriter (CPS.WriterT w') m) where - writer = lift . writer - tell = lift . tell - listen (LiftingWriter (CPS.runWriterT -> x)) = LiftingWriter $ CPS.writerT $ do - ((a, w'), w) <- listen x - pure ((a, w), w') - pass (LiftingWriter (CPS.runWriterT -> x)) = LiftingWriter $ CPS.writerT $ do - (y, w') <- x - a <- pass $ pure y - pure (a, w') + listen = LiftingWriterInternal . mapLiftingWriter (fmap hammer . listen) . runLiftingWriterInternal + where hammer ((a, s, w'), w) = ((a, w), s, w') + pass = LiftingWriterInternal . mapLiftingWriter (pass . fmap hammer) . runLiftingWriterInternal + where hammer ((a, f), s, w') = ((a, s, w'), f) + +deriving via LiftingWriterInternal (SwapWS rwst r s w') m + instance + (MonadWriter w (LiftingWriter (rwst r w' s) m), MonadWriter w m, MonadTrans (SwapWS rwst r s w'), Monad (SwapWS rwst r s w' m), Monad (rwst r w' s m), Monoid w', MapLiftingWriter s (SwapWS rwst r s)) => + MonadWriter w (LiftingWriter (rwst r w' s) m) +--deriving via LiftingWriterInternal (SwapWS LazyRWS.RWST r s w') m +-- instance +-- (MonadWriter w m, Monad (SwapWS LazyRWS.RWST r s w' m), MonadTrans (SwapWS LazyRWS.RWST r s w'), Monoid w') => +-- MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) +-- +--deriving via LiftingWriterInternal (SwapWS StrictRWS.RWST r s w') m +-- instance +-- (MonadWriter w m, Monad (SwapWS StrictRWS.RWST r s w' m), MonadTrans (SwapWS StrictRWS.RWST r s w'), Monoid w') => +-- MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) +-- +--deriving via LiftingWriterInternal (SwapWS CPSRWS.RWST r s w') m +-- instance +-- (MonadWriter w m, Monad (SwapWS CPSRWS.RWST r s w' m), MonadTrans (SwapWS CPSRWS.RWST r s w'), Monoid w') => +-- MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) + +class MapLiftingWriter s t | t -> s where + mapLiftingWriter :: (Functor m, Monad n, Monoid w, Monoid w') => (m (a,s,w) -> n (b,s,w')) -> t w m a -> t w' n b + +newtype SwapWS rwst r s w (m :: Type -> Type) a = SwapWS {runSwapWS :: rwst r w s m a} + +wrapMapWriterRWST + :: ((m (a, s, w) -> n (b, s, w')) -> rwst r w s m a -> rwst r w' s n b) + -> (m (a, s, w) -> n (b, s, w')) + -> SwapWS rwst r s w m a + -> SwapWS rwst r s w' n b +wrapMapWriterRWST map f = SwapWS . map f . runSwapWS + +instance MapLiftingWriter s (SwapWS LazyRWS.RWST r s) where + mapLiftingWriter = wrapMapWriterRWST LazyRWS.mapRWST + +instance MapLiftingWriter s (SwapWS StrictRWS.RWST r s) where + mapLiftingWriter = wrapMapWriterRWST StrictRWS.mapRWST + +instance MapLiftingWriter s (SwapWS CPSRWS.RWST r s) where + mapLiftingWriter = wrapMapWriterRWST CPSRWS.mapRWST + +wrapMapWriterT + :: (Functor m, Functor n) + => ((m (a, w) -> n (b, w')) -> writerT w m a -> writerT w' n b) + -> (m (a, (), w) -> n (b, (), w')) + -> writerT w m a + -> writerT w' n b +wrapMapWriterT map f = map $ fmap removeTuple . f . fmap insertTuple + where + insertTuple (a,w) = (a,(),w) + removeTuple (b,(),w) = (b,w) + +instance MapLiftingWriter () Lazy.WriterT where + mapLiftingWriter = wrapMapWriterT Lazy.mapWriterT + +instance MapLiftingWriter () Strict.WriterT where + mapLiftingWriter = wrapMapWriterT Strict.mapWriterT + +instance MapLiftingWriter () CPS.WriterT where + mapLiftingWriter = wrapMapWriterT CPS.mapWriterT From 72a6089506677754faa0e4b7bc6253df5d9f7194 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Wed, 15 May 2024 09:52:27 -0400 Subject: [PATCH 06/12] using mapping functions for LiftingWriter --- Control/Monad/Writer/Class.hs | 133 +++++++++++++--------------------- 1 file changed, 50 insertions(+), 83 deletions(-) diff --git a/Control/Monad/Writer/Class.hs b/Control/Monad/Writer/Class.hs index 0fa78b0..34ec7a6 100644 --- a/Control/Monad/Writer/Class.hs +++ b/Control/Monad/Writer/Class.hs @@ -1,15 +1,10 @@ -{-# LANGUAGE Trustworthy #-} {-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE StandaloneKindSignatures #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE DerivingVia #-} -{-# OPTIONS_GHC -Wno-name-shadowing #-} +{-# LANGUAGE Trustworthy #-} +{-# LANGUAGE UndecidableInstances #-} -- Search for UndecidableInstances to see why this is needed ----------------------------------------------------------------------------- @@ -57,6 +52,7 @@ import qualified Control.Monad.Trans.RWS.CPS as CPSRWS import qualified Control.Monad.Trans.Writer.CPS as CPS import Control.Monad.Trans.Class (MonadTrans(lift)) import Data.Kind (Type) +import Data.Coerce (coerce) -- --------------------------------------------------------------------------- -- MonadWriter class @@ -215,84 +211,55 @@ instance listen = Accum.liftListen listen pass = Accum.liftPass pass - --- | A helper type to decrease boilerplate when defining new transformer --- instances of 'MonadWriter'. --- --- @since ???? type LiftingWriter :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type newtype LiftingWriter t m a = LiftingWriter {runLiftingWriter :: t m a} deriving (Functor, Applicative, Monad, MonadTrans) -type LiftingWriterInternal :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type -newtype LiftingWriterInternal t m a = LiftingWriterInternal {runLiftingWriterInternal :: t m a} - deriving (Functor, Applicative, Monad, MonadTrans) +mapLiftingWriter :: (t m a -> t m b) -> LiftingWriter t m a -> LiftingWriter t m b +mapLiftingWriter = coerce -instance (MonadWriter w m, MonadTrans (t w'), Monad (t w' m), Monoid w', MapLiftingWriter s t) => MonadWriter w (LiftingWriterInternal (t w') m) where - writer = lift . writer - tell = lift . tell - listen = LiftingWriterInternal . mapLiftingWriter (fmap hammer . listen) . runLiftingWriterInternal - where hammer ((a, s, w'), w) = ((a, w), s, w') - pass = LiftingWriterInternal . mapLiftingWriter (pass . fmap hammer) . runLiftingWriterInternal - where hammer ((a, f), s, w') = ((a, s, w'), f) - -deriving via LiftingWriterInternal (SwapWS rwst r s w') m - instance - (MonadWriter w (LiftingWriter (rwst r w' s) m), MonadWriter w m, MonadTrans (SwapWS rwst r s w'), Monad (SwapWS rwst r s w' m), Monad (rwst r w' s m), Monoid w', MapLiftingWriter s (SwapWS rwst r s)) => - MonadWriter w (LiftingWriter (rwst r w' s) m) ---deriving via LiftingWriterInternal (SwapWS LazyRWS.RWST r s w') m --- instance --- (MonadWriter w m, Monad (SwapWS LazyRWS.RWST r s w' m), MonadTrans (SwapWS LazyRWS.RWST r s w'), Monoid w') => --- MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) --- ---deriving via LiftingWriterInternal (SwapWS StrictRWS.RWST r s w') m --- instance --- (MonadWriter w m, Monad (SwapWS StrictRWS.RWST r s w' m), MonadTrans (SwapWS StrictRWS.RWST r s w'), Monoid w') => --- MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) --- ---deriving via LiftingWriterInternal (SwapWS CPSRWS.RWST r s w') m --- instance --- (MonadWriter w m, Monad (SwapWS CPSRWS.RWST r s w' m), MonadTrans (SwapWS CPSRWS.RWST r s w'), Monoid w') => --- MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) - -class MapLiftingWriter s t | t -> s where - mapLiftingWriter :: (Functor m, Monad n, Monoid w, Monoid w') => (m (a,s,w) -> n (b,s,w')) -> t w m a -> t w' n b - -newtype SwapWS rwst r s w (m :: Type -> Type) a = SwapWS {runSwapWS :: rwst r w s m a} - -wrapMapWriterRWST - :: ((m (a, s, w) -> n (b, s, w')) -> rwst r w s m a -> rwst r w' s n b) - -> (m (a, s, w) -> n (b, s, w')) - -> SwapWS rwst r s w m a - -> SwapWS rwst r s w' n b -wrapMapWriterRWST map f = SwapWS . map f . runSwapWS - -instance MapLiftingWriter s (SwapWS LazyRWS.RWST r s) where - mapLiftingWriter = wrapMapWriterRWST LazyRWS.mapRWST - -instance MapLiftingWriter s (SwapWS StrictRWS.RWST r s) where - mapLiftingWriter = wrapMapWriterRWST StrictRWS.mapRWST - -instance MapLiftingWriter s (SwapWS CPSRWS.RWST r s) where - mapLiftingWriter = wrapMapWriterRWST CPSRWS.mapRWST - -wrapMapWriterT - :: (Functor m, Functor n) - => ((m (a, w) -> n (b, w')) -> writerT w m a -> writerT w' n b) - -> (m (a, (), w) -> n (b, (), w')) - -> writerT w m a - -> writerT w' n b -wrapMapWriterT map f = map $ fmap removeTuple . f . fmap insertTuple - where - insertTuple (a,w) = (a,(),w) - removeTuple (b,(),w) = (b,w) - -instance MapLiftingWriter () Lazy.WriterT where - mapLiftingWriter = wrapMapWriterT Lazy.mapWriterT - -instance MapLiftingWriter () Strict.WriterT where - mapLiftingWriter = wrapMapWriterT Strict.mapWriterT - -instance MapLiftingWriter () CPS.WriterT where - mapLiftingWriter = wrapMapWriterT CPS.mapWriterT +formatWriter :: ((a,b),c) -> ((a,c),b) +formatWriter ((a,b),c) = ((a,c),b) + +instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (Lazy.WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftingWriter $ Lazy.mapWriterT $ fmap formatWriter . listen + pass = mapLiftingWriter $ Lazy.mapWriterT $ pass . fmap formatWriter + +instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (Strict.WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftingWriter $ Strict.mapWriterT $ fmap formatWriter . listen + pass = mapLiftingWriter $ Strict.mapWriterT $ pass . fmap formatWriter + +instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (CPS.WriterT w') m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftingWriter $ CPS.mapWriterT $ fmap formatWriter . listen + pass = mapLiftingWriter $ CPS.mapWriterT $ pass . fmap formatWriter + +formatListenRWS :: ((a,b,c),d) -> ((a,d),b,c) +formatListenRWS ((a,b,c),d) = ((a,d),b,c) + +formatPassRWS :: ((a,b),c,d) -> ((a,c,d),b) +formatPassRWS ((a,b),c,d) = ((a,c,d),b) + +instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftingWriter $ LazyRWS.mapRWST $ fmap formatListenRWS . listen + pass = mapLiftingWriter $ LazyRWS.mapRWST $ pass . fmap formatPassRWS + +instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftingWriter $ StrictRWS.mapRWST $ fmap formatListenRWS . listen + pass = mapLiftingWriter $ StrictRWS.mapRWST $ pass . fmap formatPassRWS + +instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftingWriter $ CPSRWS.mapRWST $ fmap formatListenRWS . listen + pass = mapLiftingWriter $ CPSRWS.mapRWST $ pass . fmap formatPassRWS From a40942d1769ac78598b2798ddf3e5888fcc15b2b Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Wed, 15 May 2024 10:01:26 -0400 Subject: [PATCH 07/12] using mapping functions for LiftingReader --- Control/Monad/Reader/Class.hs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index 4eed77f..4be5bd3 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -74,6 +74,7 @@ import qualified Control.Monad.Trans.RWS.CPS as CPSRWS import qualified Control.Monad.Trans.Writer.CPS as CPS import Control.Monad.Trans.Class (MonadTrans(lift)) import Data.Kind (Type) +import Data.Coerce (coerce) -- ---------------------------------------------------------------------------- -- class MonadReader @@ -216,22 +217,26 @@ type LiftingReader :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type newtype LiftingReader t m a = LiftingReader (t m a) deriving (Functor, Applicative, Monad, MonadTrans) +mapLiftingReader :: (t m a -> t m b) -> LiftingReader t m a -> LiftingReader t m b +mapLiftingReader = coerce + instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (LazyRWS.RWST r' w s) m) where ask = lift ask - local f (LiftingReader (LazyRWS.RWST x)) = LiftingReader . LazyRWS.RWST $ \r s -> local f $ x r s + local = mapLiftingReader . LazyRWS.mapRWST . local reader = lift . reader instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (StrictRWS.RWST r' w s) m) where ask = lift ask - local f (LiftingReader (StrictRWS.RWST x)) = LiftingReader . StrictRWS.RWST $ \r s -> local f $ x r s + local = mapLiftingReader . StrictRWS.mapRWST . local reader = lift . reader instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (CPSRWS.RWST r' w s) m) where ask = lift ask - local f (LiftingReader (CPSRWS.runRWST -> x)) = LiftingReader . CPSRWS.rwsT $ \r s -> local f $ x r s + local = mapLiftingReader . CPSRWS.mapRWST . local reader = lift . reader instance MonadReader r m => MonadReader r (LiftingReader (ReaderT r') m) where ask = lift ask - local f (LiftingReader (ReaderT.ReaderT x)) = LiftingReader . ReaderT.ReaderT $ local f . x + local = mapLiftingReader . ReaderT.mapReaderT . local reader = lift . reader + From 6a8889467294d95a97671e39a07dc7fdc0556bd2 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Thu, 16 May 2024 09:02:16 -0400 Subject: [PATCH 08/12] fixed comment --- Control/Monad/Reader/Class.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index 4be5bd3..d15a974 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -4,12 +4,12 @@ {-# LANGUAGE MultiParamTypeClasses #-} -- Search for UndecidableInstances to see why this is needed {-# LANGUAGE UndecidableInstances #-} --- Needed because the CPSed versions of Writer and State are secretly State --- wrappers, which don't force such constraints, even though they should legally --- be there. {-# LANGUAGE StandaloneKindSignatures #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ViewPatterns #-} +-- Needed because the CPSed versions of Writer and State are secretly State +-- wrappers, which don't force such constraints, even though they should legally +-- be there. {-# OPTIONS_GHC -Wno-redundant-constraints #-} {- | Module : Control.Monad.Reader.Class From eca747d2d96a224b891065ccbc005f1a9020cd05 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Fri, 17 May 2024 09:05:38 -0400 Subject: [PATCH 09/12] fixed exports, added doc comments --- Control/Monad/Reader.hs | 2 +- Control/Monad/Reader/Class.hs | 4 ++++ Control/Monad/State/Class.hs | 3 ++- Control/Monad/State/Lazy.hs | 2 ++ Control/Monad/State/Strict.hs | 2 ++ Control/Monad/Writer/CPS.hs | 4 ++-- Control/Monad/Writer/Class.hs | 9 +++++++++ Control/Monad/Writer/Lazy.hs | 4 ++-- Control/Monad/Writer/Strict.hs | 4 ++-- 9 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Control/Monad/Reader.hs b/Control/Monad/Reader.hs index ba98d53..cabd2dc 100644 --- a/Control/Monad/Reader.hs +++ b/Control/Monad/Reader.hs @@ -41,7 +41,7 @@ module Control.Monad.Reader ( MonadReader.MonadReader(..), MonadReader.asks, -- * Lifting helper type - MonadReader.LiftingReader, + MonadReader.LiftingReader(..), -- * The Reader monad Reader, runReader, diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index d15a974..c059599 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -220,21 +220,25 @@ newtype LiftingReader t m a = LiftingReader (t m a) mapLiftingReader :: (t m a -> t m b) -> LiftingReader t m a -> LiftingReader t m b mapLiftingReader = coerce +-- | @since ???? instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (LazyRWS.RWST r' w s) m) where ask = lift ask local = mapLiftingReader . LazyRWS.mapRWST . local reader = lift . reader +-- | @since ???? instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (StrictRWS.RWST r' w s) m) where ask = lift ask local = mapLiftingReader . StrictRWS.mapRWST . local reader = lift . reader +-- | @since ???? instance (MonadReader r m, Monoid w) => MonadReader r (LiftingReader (CPSRWS.RWST r' w s) m) where ask = lift ask local = mapLiftingReader . CPSRWS.mapRWST . local reader = lift . reader +-- | @since ???? instance MonadReader r m => MonadReader r (LiftingReader (ReaderT r') m) where ask = lift ask local = mapLiftingReader . ReaderT.mapReaderT . local diff --git a/Control/Monad/State/Class.hs b/Control/Monad/State/Class.hs index c523be4..f5412a3 100644 --- a/Control/Monad/State/Class.hs +++ b/Control/Monad/State/Class.hs @@ -36,7 +36,7 @@ module Control.Monad.State.Class ( modify, modify', gets, - LiftingState + LiftingState(..), ) where import Control.Monad.Trans.Cont (ContT) @@ -205,6 +205,7 @@ type LiftingState :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type newtype LiftingState t m a = LiftingState (t m a) deriving (Functor, Applicative, Monad, MonadTrans) +-- | @since ???? instance (MonadState s m, MonadTrans t, Monad (t m)) => MonadState s (LiftingState t m) where get = lift get put = lift . put diff --git a/Control/Monad/State/Lazy.hs b/Control/Monad/State/Lazy.hs index 98241d6..c57e733 100644 --- a/Control/Monad/State/Lazy.hs +++ b/Control/Monad/State/Lazy.hs @@ -39,6 +39,8 @@ module Control.Monad.State.Lazy ( execStateT, mapStateT, withStateT, + -- * Lifting helper type + MonadState.LiftingState(..), module Control.Monad.Trans, -- * Examples -- $examples diff --git a/Control/Monad/State/Strict.hs b/Control/Monad/State/Strict.hs index 5c9d93f..81d3a20 100644 --- a/Control/Monad/State/Strict.hs +++ b/Control/Monad/State/Strict.hs @@ -39,6 +39,8 @@ module Control.Monad.State.Strict ( execStateT, mapStateT, withStateT, + -- * Lifting helper type + MonadState.LiftingState(..), module Control.Monad.Trans, -- * Examples -- $examples diff --git a/Control/Monad/Writer/CPS.hs b/Control/Monad/Writer/CPS.hs index 4ecd36c..fad3913 100644 --- a/Control/Monad/Writer/CPS.hs +++ b/Control/Monad/Writer/CPS.hs @@ -26,8 +26,6 @@ module Control.Monad.Writer.CPS ( MonadWriter.MonadWriter(..), MonadWriter.listens, MonadWriter.censor, - -- * Lifting helper type - MonadWriter.LiftingWriter, -- * The Writer monad Writer, runWriter, @@ -37,6 +35,8 @@ module Control.Monad.Writer.CPS ( WriterT, execWriterT, mapWriterT, + -- * Lifting helper type + MonadWriter.LiftingWriter(..), module Control.Monad.Trans, ) where diff --git a/Control/Monad/Writer/Class.hs b/Control/Monad/Writer/Class.hs index 34ec7a6..f55c750 100644 --- a/Control/Monad/Writer/Class.hs +++ b/Control/Monad/Writer/Class.hs @@ -221,18 +221,24 @@ mapLiftingWriter = coerce formatWriter :: ((a,b),c) -> ((a,c),b) formatWriter ((a,b),c) = ((a,c),b) +-- | A helper type to decrease boilerplate when defining new transformer +-- instances of 'MonadState'. +-- +-- @since ???? instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (Lazy.WriterT w') m) where writer = lift . writer tell = lift . tell listen = mapLiftingWriter $ Lazy.mapWriterT $ fmap formatWriter . listen pass = mapLiftingWriter $ Lazy.mapWriterT $ pass . fmap formatWriter +-- | @since ???? instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (Strict.WriterT w') m) where writer = lift . writer tell = lift . tell listen = mapLiftingWriter $ Strict.mapWriterT $ fmap formatWriter . listen pass = mapLiftingWriter $ Strict.mapWriterT $ pass . fmap formatWriter +-- | @since ???? instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (CPS.WriterT w') m) where writer = lift . writer tell = lift . tell @@ -245,18 +251,21 @@ formatListenRWS ((a,b,c),d) = ((a,d),b,c) formatPassRWS :: ((a,b),c,d) -> ((a,c,d),b) formatPassRWS ((a,b),c,d) = ((a,c,d),b) +-- | @since ???? instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) where writer = lift . writer tell = lift . tell listen = mapLiftingWriter $ LazyRWS.mapRWST $ fmap formatListenRWS . listen pass = mapLiftingWriter $ LazyRWS.mapRWST $ pass . fmap formatPassRWS +-- | @since ???? instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) where writer = lift . writer tell = lift . tell listen = mapLiftingWriter $ StrictRWS.mapRWST $ fmap formatListenRWS . listen pass = mapLiftingWriter $ StrictRWS.mapRWST $ pass . fmap formatPassRWS +-- | @since ???? instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) where writer = lift . writer tell = lift . tell diff --git a/Control/Monad/Writer/Lazy.hs b/Control/Monad/Writer/Lazy.hs index d4b7bf9..7070123 100644 --- a/Control/Monad/Writer/Lazy.hs +++ b/Control/Monad/Writer/Lazy.hs @@ -23,8 +23,6 @@ module Control.Monad.Writer.Lazy ( MonadWriter.MonadWriter(..), MonadWriter.listens, MonadWriter.censor, - -- * Lifting helper type - MonadWriter.LiftingWriter, -- * The Writer monad Writer, runWriter, @@ -35,6 +33,8 @@ module Control.Monad.Writer.Lazy ( runWriterT, execWriterT, mapWriterT, + -- * Lifting helper type + MonadWriter.LiftingWriter(..), module Control.Monad.Trans, ) where diff --git a/Control/Monad/Writer/Strict.hs b/Control/Monad/Writer/Strict.hs index 2cedb95..f1336fc 100644 --- a/Control/Monad/Writer/Strict.hs +++ b/Control/Monad/Writer/Strict.hs @@ -23,8 +23,6 @@ module Control.Monad.Writer.Strict ( MonadWriter.MonadWriter(..), MonadWriter.listens, MonadWriter.censor, - -- * Lifting helper type - MonadWriter.LiftingWriter, -- * The Writer monad Writer, runWriter, @@ -34,6 +32,8 @@ module Control.Monad.Writer.Strict ( WriterT(..), execWriterT, mapWriterT, + -- * Lifting helper type + MonadWriter.LiftingWriter(..), module Control.Monad.Trans, ) where From 6e75a307f792cbda6475724eed2e0f280e0904b7 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 19 May 2024 22:08:03 -0400 Subject: [PATCH 10/12] added example for LiftingReader and LiftingState --- Control/Monad/Reader.hs | 5 +++-- Control/Monad/Reader/Class.hs | 6 ++++++ Control/Monad/State/Class.hs | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Control/Monad/Reader.hs b/Control/Monad/Reader.hs index cabd2dc..a2c95ed 100644 --- a/Control/Monad/Reader.hs +++ b/Control/Monad/Reader.hs @@ -40,8 +40,6 @@ module Control.Monad.Reader ( -- * MonadReader class MonadReader.MonadReader(..), MonadReader.asks, - -- * Lifting helper type - MonadReader.LiftingReader(..), -- * The Reader monad Reader, runReader, @@ -52,6 +50,9 @@ module Control.Monad.Reader ( runReaderT, mapReaderT, withReaderT, + -- * Lifting helper type + MonadReader.LiftingReader(..), + -- * Lifting into the transformer module Control.Monad.Trans, -- * Example 1: Simple Reader Usage -- $simpleReaderExample diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index c059599..1567c99 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -212,6 +212,12 @@ instance -- | A helper type to decrease boilerplate when defining new transformer -- instances of 'MonadReader'. -- +-- @ +-- newtype SneakyReaderT m a = SneakyReaderT { runSneakyReaderT :: ReaderT String m a } +-- deriving (Functor, Applicative, Monad) +-- deriving (MonadReader w) via LiftingReader (ReaderT String) m +-- @ +-- -- @since ???? type LiftingReader :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type newtype LiftingReader t m a = LiftingReader (t m a) diff --git a/Control/Monad/State/Class.hs b/Control/Monad/State/Class.hs index f5412a3..397c466 100644 --- a/Control/Monad/State/Class.hs +++ b/Control/Monad/State/Class.hs @@ -200,6 +200,12 @@ instance MonadState s m => MonadState s (SelectT r m) where -- | A helper type to decrease boilerplate when defining new transformer -- instances of 'MonadState'. -- +-- @ +-- newtype SneakyStateT m a = SneakyStateT { runSneakyStateT :: Lazy.StateT String m a } +-- deriving (Functor, Applicative, Monad) +-- deriving (MonadState w) via LiftingState (Lazy.StateT String) m +-- @ +-- -- @since ???? type LiftingState :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type newtype LiftingState t m a = LiftingState (t m a) From b701e12fb840bb488d5785bc21a9a8e67fd0b58a Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 19 May 2024 22:10:42 -0400 Subject: [PATCH 11/12] Swithced to using a polykinded type family LiftingWriter. Allows for more convenient deriving. --- Control/Monad/State/Lazy.hs | 1 + Control/Monad/State/Strict.hs | 1 + Control/Monad/Writer/CPS.hs | 5 +- Control/Monad/Writer/Class.hs | 129 +++++++++++++++++++++------------ Control/Monad/Writer/Lazy.hs | 5 +- Control/Monad/Writer/Strict.hs | 5 +- 6 files changed, 95 insertions(+), 51 deletions(-) diff --git a/Control/Monad/State/Lazy.hs b/Control/Monad/State/Lazy.hs index c57e733..3d90381 100644 --- a/Control/Monad/State/Lazy.hs +++ b/Control/Monad/State/Lazy.hs @@ -41,6 +41,7 @@ module Control.Monad.State.Lazy ( withStateT, -- * Lifting helper type MonadState.LiftingState(..), + -- * Lifting into the transformer module Control.Monad.Trans, -- * Examples -- $examples diff --git a/Control/Monad/State/Strict.hs b/Control/Monad/State/Strict.hs index 81d3a20..33f7da1 100644 --- a/Control/Monad/State/Strict.hs +++ b/Control/Monad/State/Strict.hs @@ -41,6 +41,7 @@ module Control.Monad.State.Strict ( withStateT, -- * Lifting helper type MonadState.LiftingState(..), + -- * Lifting into the transformer module Control.Monad.Trans, -- * Examples -- $examples diff --git a/Control/Monad/Writer/CPS.hs b/Control/Monad/Writer/CPS.hs index fad3913..d9b74b9 100644 --- a/Control/Monad/Writer/CPS.hs +++ b/Control/Monad/Writer/CPS.hs @@ -36,7 +36,10 @@ module Control.Monad.Writer.CPS ( execWriterT, mapWriterT, -- * Lifting helper type - MonadWriter.LiftingWriter(..), + MonadWriter.LiftingWriter, + MonadWriter.LiftWriter(..), + MonadWriter.LiftWriterRWS(..), + -- * Lifting into the transformer module Control.Monad.Trans, ) where diff --git a/Control/Monad/Writer/Class.hs b/Control/Monad/Writer/Class.hs index f55c750..b392481 100644 --- a/Control/Monad/Writer/Class.hs +++ b/Control/Monad/Writer/Class.hs @@ -5,6 +5,12 @@ {-# LANGUAGE StandaloneKindSignatures #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeFamilies #-} + +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE DerivingVia #-} -- Search for UndecidableInstances to see why this is needed ----------------------------------------------------------------------------- @@ -30,7 +36,9 @@ module Control.Monad.Writer.Class ( MonadWriter(..), listens, censor, - LiftingWriter(..), + LiftingWriter, + LiftWriter(..), + LiftWriterRWS(..), ) where import Control.Monad.Trans.Except (ExceptT) @@ -51,7 +59,7 @@ import qualified Control.Monad.Trans.Accum as Accum import qualified Control.Monad.Trans.RWS.CPS as CPSRWS import qualified Control.Monad.Trans.Writer.CPS as CPS import Control.Monad.Trans.Class (MonadTrans(lift)) -import Data.Kind (Type) +import Data.Kind (Type, Constraint) import Data.Coerce (coerce) -- --------------------------------------------------------------------------- @@ -211,64 +219,89 @@ instance listen = Accum.liftListen listen pass = Accum.liftPass pass -type LiftingWriter :: ((Type -> Type) -> Type -> Type) -> (Type -> Type) -> Type -> Type -newtype LiftingWriter t m a = LiftingWriter {runLiftingWriter :: t m a} - deriving (Functor, Applicative, Monad, MonadTrans) - -mapLiftingWriter :: (t m a -> t m b) -> LiftingWriter t m a -> LiftingWriter t m b -mapLiftingWriter = coerce +-- | A helper type function to decrease boilerplate when defining new +-- transformer instances of 'MonadWriter'. +-- +-- Example of deriving 'MonadWriter' from @m@ and not the 'Lazy.WriterT' transformer. +-- +-- @ +-- newtype SneakyWriterT m a = SneakyWriterT { runSneakyWriterT :: Lazy.WriterT String m a } +-- deriving (Functor, Applicative, Monad) +-- deriving (MonadWriter w) via LiftingWriter Lazy.WriterT String m +-- @ +-- +-- Example of deriving 'MonadWriter' from @m@ and not the 'LazyRWS.RWST' transformer. +-- +-- @ +-- newtype SneakyRWST m a = SneakyRWST { runSneakyRWST :: LazyRWS.RWST () String () m a } +-- deriving (Functor, Applicative, Monad) +-- deriving (MonadWriter w) via LiftingWriter LazyRWS.RWST () String () m +-- @ +-- +-- | @since ???? +type LiftingWriter :: forall t. t +type family LiftingWriter where + LiftingWriter = LiftWriter + LiftingWriter = LiftWriterRWS -formatWriter :: ((a,b),c) -> ((a,c),b) -formatWriter ((a,b),c) = ((a,c),b) +-- | Do not use directly; use @LiftingWriter@ instead. +-- +-- | @since ???? +newtype LiftWriter t w (m :: Type -> Type) a = LiftWriter (t w m a) + deriving (Functor, Applicative, Monad, MonadTrans) --- | A helper type to decrease boilerplate when defining new transformer --- instances of 'MonadState'. +-- | Do not use directly; use @LiftingWriter@ instead. -- --- @since ???? -instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (Lazy.WriterT w') m) where - writer = lift . writer - tell = lift . tell - listen = mapLiftingWriter $ Lazy.mapWriterT $ fmap formatWriter . listen - pass = mapLiftingWriter $ Lazy.mapWriterT $ pass . fmap formatWriter +-- | @since ???? +newtype LiftWriterRWS t r w s (m :: Type -> Type) a = LiftWriterRWS (t r w s m a) + deriving (Functor, Applicative, Monad, MonadTrans) +-- | Class that allows new writer transformers to use the existing instance of 'MonadWriter' so that they can be used with 'LiftingWriter' to using the monad's "MonadWriter' instance. +-- By using this class you only have to define 'mapWriterT' instead of 'writer', 'tell', 'listen', and 'pass'. +-- -- | @since ???? -instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (Strict.WriterT w') m) where - writer = lift . writer - tell = lift . tell - listen = mapLiftingWriter $ Strict.mapWriterT $ fmap formatWriter . listen - pass = mapLiftingWriter $ Strict.mapWriterT $ pass . fmap formatWriter +type MapWriter :: (Type -> (Type -> Type) -> Type -> Type) -> Constraint +class MapWriter t where mapWriterT :: (Monad m, Monoid w) => (m (a, w) -> m (b, w)) -> t w m a -> t w m b +-- | @since ???? +instance MapWriter Lazy.WriterT where mapWriterT = Lazy.mapWriterT +-- | @since ???? +instance MapWriter Strict.WriterT where mapWriterT = Strict.mapWriterT +-- | @since ???? +instance MapWriter CPS.WriterT where mapWriterT = CPS.mapWriterT +-- | Class that allows new reader writer state transformers to use the existing instance of 'MonadWriter' so that they can be used with 'LiftingWriter' to using the monad's "MonadWriter' instance. +-- By using this class you only have to define 'mapRWST' instead of 'writer', 'tell', 'listen', and 'pass'. +-- -- | @since ???? -instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (CPS.WriterT w') m) where - writer = lift . writer - tell = lift . tell - listen = mapLiftingWriter $ CPS.mapWriterT $ fmap formatWriter . listen - pass = mapLiftingWriter $ CPS.mapWriterT $ pass . fmap formatWriter +type MapRWS :: (Type -> Type -> Type -> (Type -> Type) -> Type -> Type) -> Constraint +class MapRWS t where mapRWST :: (Monad m, Monoid w) => (m (a, s, w) -> m (b, s, w)) -> t r w s m a -> t r w s m b +-- | @since ???? +instance MapRWS LazyRWS.RWST where mapRWST = LazyRWS.mapRWST +-- | @since ???? +instance MapRWS StrictRWS.RWST where mapRWST = StrictRWS.mapRWST +-- | @since ???? +instance MapRWS CPSRWS.RWST where mapRWST = CPSRWS.mapRWST -formatListenRWS :: ((a,b,c),d) -> ((a,d),b,c) -formatListenRWS ((a,b,c),d) = ((a,d),b,c) +mapLiftWriter :: (t w m a -> t w m b) -> LiftWriter t w m a -> LiftWriter t w m b +mapLiftWriter = coerce -formatPassRWS :: ((a,b),c,d) -> ((a,c,d),b) -formatPassRWS ((a,b),c,d) = ((a,c,d),b) +formatWriter :: ((a,b),c) -> ((a,c),b) +formatWriter ((a,b),c) = ((a,c),b) --- | @since ???? -instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (LazyRWS.RWST r w' s) m) where - writer = lift . writer - tell = lift . tell - listen = mapLiftingWriter $ LazyRWS.mapRWST $ fmap formatListenRWS . listen - pass = mapLiftingWriter $ LazyRWS.mapRWST $ pass . fmap formatPassRWS +mapLiftWriterRWS :: (t r w s m a -> t r w s m b) -> LiftWriterRWS t r w s m a -> LiftWriterRWS t r w s m b +mapLiftWriterRWS = coerce -- | @since ???? -instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (StrictRWS.RWST r w' s) m) where - writer = lift . writer - tell = lift . tell - listen = mapLiftingWriter $ StrictRWS.mapRWST $ fmap formatListenRWS . listen - pass = mapLiftingWriter $ StrictRWS.mapRWST $ pass . fmap formatPassRWS +instance (MapWriter t, MonadWriter w m, MonadTrans (t w'), Monad (t w' m), Monoid w') => MonadWriter w (LiftWriter t w' m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftWriter $ mapWriterT $ fmap formatWriter . listen + pass = mapLiftWriter $ mapWriterT $ pass . fmap formatWriter -- | @since ???? -instance (MonadWriter w m, Monoid w') => MonadWriter w (LiftingWriter (CPSRWS.RWST r w' s) m) where - writer = lift . writer - tell = lift . tell - listen = mapLiftingWriter $ CPSRWS.mapRWST $ fmap formatListenRWS . listen - pass = mapLiftingWriter $ CPSRWS.mapRWST $ pass . fmap formatPassRWS +instance (MapRWS t, MonadWriter w m, MonadTrans (t r w' s), Monad (t r w' s m), Monoid w') => MonadWriter w (LiftWriterRWS t r w' s m) where + writer = lift . writer + tell = lift . tell + listen = mapLiftWriterRWS $ mapRWST $ fmap (\((a,b,c),d) -> ((a,d),b,c)) . listen + pass = mapLiftWriterRWS $ mapRWST $ pass . fmap (\((a,b),c,d) -> ((a,c,d),b)) diff --git a/Control/Monad/Writer/Lazy.hs b/Control/Monad/Writer/Lazy.hs index 7070123..ff60e87 100644 --- a/Control/Monad/Writer/Lazy.hs +++ b/Control/Monad/Writer/Lazy.hs @@ -34,7 +34,10 @@ module Control.Monad.Writer.Lazy ( execWriterT, mapWriterT, -- * Lifting helper type - MonadWriter.LiftingWriter(..), + MonadWriter.LiftingWriter, + MonadWriter.LiftWriter(..), + MonadWriter.LiftWriterRWS(..), + -- * Lifting into the transformer module Control.Monad.Trans, ) where diff --git a/Control/Monad/Writer/Strict.hs b/Control/Monad/Writer/Strict.hs index f1336fc..b4588a2 100644 --- a/Control/Monad/Writer/Strict.hs +++ b/Control/Monad/Writer/Strict.hs @@ -33,7 +33,10 @@ module Control.Monad.Writer.Strict ( execWriterT, mapWriterT, -- * Lifting helper type - MonadWriter.LiftingWriter(..), + MonadWriter.LiftingWriter, + MonadWriter.LiftWriter(..), + MonadWriter.LiftWriterRWS(..), + -- * Lifting into the transformer module Control.Monad.Trans, ) where From 222f6f91bf3ca8ea4ec4e68a3f38c196c07ec97b Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Thu, 25 Jul 2024 14:09:48 -0400 Subject: [PATCH 12/12] fixed reader and state type variables --- Control/Monad/Reader/Class.hs | 2 +- Control/Monad/State/Class.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs index 1567c99..c95f24e 100644 --- a/Control/Monad/Reader/Class.hs +++ b/Control/Monad/Reader/Class.hs @@ -215,7 +215,7 @@ instance -- @ -- newtype SneakyReaderT m a = SneakyReaderT { runSneakyReaderT :: ReaderT String m a } -- deriving (Functor, Applicative, Monad) --- deriving (MonadReader w) via LiftingReader (ReaderT String) m +-- deriving (MonadReader r) via LiftingReader (ReaderT String) m -- @ -- -- @since ???? diff --git a/Control/Monad/State/Class.hs b/Control/Monad/State/Class.hs index 397c466..ba4d25c 100644 --- a/Control/Monad/State/Class.hs +++ b/Control/Monad/State/Class.hs @@ -203,7 +203,7 @@ instance MonadState s m => MonadState s (SelectT r m) where -- @ -- newtype SneakyStateT m a = SneakyStateT { runSneakyStateT :: Lazy.StateT String m a } -- deriving (Functor, Applicative, Monad) --- deriving (MonadState w) via LiftingState (Lazy.StateT String) m +-- deriving (MonadState s) via LiftingState (Lazy.StateT String) m -- @ -- -- @since ????