on master help sign in
Update tagging system
commit6bf12f92c60ff0d2a830159063a34f473da4517b authorIndex Int <vlad.z.4096@gmail.com> dateFri 12 Jun 2015, 21:06 (11 years ago) parent4e98fe4
4 files changed+140−94
src/Control/Ether/Tags.hs+81−30 src/Control/Monad/Trans/Ether/Except.hs+19−21 src/Control/Monad/Trans/Ether/Reader.hs+17−19 src/Control/Monad/Trans/Ether/State.hs+23−24
src/Control/Ether/Tags.hs+81−30
@@ -4,8 +4,12 @@
44{-# LANGUAGE ConstraintKinds #-}
55{-# LANGUAGE TypeOperators #-}
66{-# LANGUAGE UndecidableInstances #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE FunctionalDependencies #-}
79module Control.Ether.Tags
8− ( Tags
10+ ( Taggable(..)
11+ , Tagged(..)
12+ , Tags
913 , UniqueTag
1014 , UniqueTags
1115 , ensureUniqueTags
@@ -58,32 +62,79 @@ type family UniqueTags (m :: * -> *) :: Constraint where
5862ensureUniqueTags :: UniqueTags m => m a -> m a
5963ensureUniqueTags = id
6064
61−-- |
62−-- The 'Tags' type family returns a type-level list of all tags of its argument
63−-- @m@. Simple monads have no tags, monad transformers propagate the tags of
64−-- their inner monads, and tagged monad transformers also add their own tag.
65−type family Tags (m :: * -> *) :: [*]
66−
67−type instance Tags IO = '[]
68−type instance Tags Identity = '[]
69−type instance Tags [] = '[]
70−type instance Tags Maybe = '[]
71−type instance Tags Last = '[]
72−type instance Tags First = '[]
73−type instance Tags ((->) r) = '[]
74−type instance Tags STM = '[]
75−type instance Tags (Either e) = '[]
76−type instance Tags Proxy = '[]
77−type instance Tags (Strict.ST s) = '[]
78−type instance Tags (Lazy.ST s) = '[]
79−
80−type instance Tags (Trans.ContT r m) = Tags m
81−type instance Tags (Trans.ExceptT e m) = Tags m
82−type instance Tags (Trans.IdentityT m) = Tags m
83−type instance Tags (Trans.ListT m) = Tags m
84−type instance Tags (Trans.MaybeT m) = Tags m
85−type instance Tags (Trans.ReaderT r m) = Tags m
86−type instance Tags (Trans.Lazy.StateT s m) = Tags m
87−type instance Tags (Trans.Strict.StateT s m) = Tags m
88−type instance Tags (Trans.Lazy.WriterT w m) = Tags m
89−type instance Tags (Trans.Strict.WriterT w m) = Tags m
65+type family MaybeToList (mt :: Maybe *) :: [*] where
66+ MaybeToList 'Nothing = '[]
67+ MaybeToList ('Just t) = '[t]
68+
69+type family (as :: [*]) ++ (bs :: [*]) :: [*] where
70+ '[] ++ bs = bs
71+ (a ': as) ++ bs = a ': (as ++ bs)
72+
73+-- | The 'Taggable' class defines the type families to manage tags in monad
74+-- transformer stacks. Its kind is restricted to @* -> *@ to prevent incorrect
75+-- instances.
76+class Taggable (m :: * -> *) where
77+
78+ -- | The 'Tag' type family equals @Nothing@ for most types, but for tagged
79+ -- monad transformers it equals @Just tag@.
80+ type Tag m :: Maybe *
81+ type instance Tag m = 'Nothing
82+
83+ -- | The 'Tags'' type family returns a type-level list of the inner monad
84+ -- of a monad transformer. Instances should be defined by passing the inner
85+ -- monad to the 'Tags' type function.
86+ type Tags' m :: [*]
87+ type instance Tags' m = '[]
88+
89+instance Taggable IO
90+instance Taggable Identity
91+
92+instance Taggable Maybe
93+instance Taggable Last
94+instance Taggable First
95+instance Taggable ((->) r)
96+instance Taggable STM
97+instance Taggable (Either e)
98+instance Taggable Proxy
99+instance Taggable (Strict.ST s)
100+instance Taggable (Lazy.ST s)
101+
102+instance Taggable (Trans.ContT r m) where
103+ type Tags' (Trans.ContT r m) = Tags m
104+
105+instance Taggable (Trans.ExceptT e m) where
106+ type Tags' (Trans.ExceptT e m) = Tags m
107+
108+instance Taggable (Trans.IdentityT m) where
109+ type Tags' (Trans.IdentityT m) = Tags m
110+
111+instance Taggable (Trans.ListT m) where
112+ type Tags' (Trans.ListT m) = Tags m
113+
114+instance Taggable (Trans.MaybeT m) where
115+ type Tags' (Trans.MaybeT m) = Tags m
116+
117+instance Taggable (Trans.ReaderT r m) where
118+ type Tags' (Trans.ReaderT r m) = Tags m
119+
120+instance Taggable (Trans.Lazy.StateT s m) where
121+ type Tags' (Trans.Lazy.StateT s m) = Tags m
122+
123+instance Taggable (Trans.Strict.StateT s m) where
124+ type Tags' (Trans.Strict.StateT s m) = Tags m
125+
126+instance Taggable (Trans.Lazy.WriterT w m) where
127+ type Tags' (Trans.Lazy.WriterT w m) = Tags m
128+
129+instance Taggable (Trans.Strict.WriterT w m) where
130+ type Tags' (Trans.Strict.WriterT w m) = Tags m
131+
132+-- | The 'Tags' type function combines the results of 'Tag' and 'Tags''.
133+type Tags (m :: * -> *) = MaybeToList (Tag m) ++ Tags' m
134+
135+-- | The 'Tagged' type class establishes a relationship between a tagged
136+-- monad transformer and its untagged counterpart.
137+class (Taggable m, Tag m ~ 'Just tag) => Tagged m tag | m -> tag where
138+ type Untagged m :: * -> *
139+ tagged :: proxy tag -> Untagged m a -> m a
140+ untagged :: proxy tag -> m a -> Untagged m a
src/Control/Monad/Trans/Ether/Except.hs+19−21
@@ -25,9 +25,6 @@ module Control.Monad.Trans.Ether.Except
2525 , liftListen
2626 , liftPass
2727 , liftCatch
28− -- * Wrapping operations
29− , tagWrap
30− , tagUnwrap
3128 ) where
3229
3330import Data.Proxy (Proxy(Proxy))
@@ -38,7 +35,7 @@ import Control.Monad (MonadPlus)
3835import Control.Monad.Fix (MonadFix)
3936import Control.Monad.Trans.Class (MonadTrans, lift)
4037import Control.Monad.IO.Class (MonadIO)
41−import Control.Ether.Tags (Tags)
38+import Control.Ether.Tags (Taggable(..), Tagged(..), Tags)
4239import qualified Control.Ether.Util as Util
4340
4441import qualified Control.Monad.Signatures as Sig
@@ -61,7 +58,7 @@ type Except tag e = ExceptT tag e Identity
6158
6259-- | Runs an 'Except' and returns either an exception or a normal value.
6360runExcept :: proxy tag -> Except tag e a -> Either e a
64−runExcept t = Trans.runExcept . tagUnwrap t
61+runExcept t = Trans.runExcept . untagged t
6562
6663-- | The exception monad transformer.
6764--
@@ -72,26 +69,27 @@ newtype ExceptT tag e m a = ExceptT (Trans.ExceptT e m a)
7269 deriving ( Functor, Applicative, Alternative, Monad, MonadPlus
7370 , MonadFix, MonadTrans, MonadIO )
7471
75−tagWrap :: proxy tag -> Trans.ExceptT e m a -> ExceptT tag e m a
76−tagWrap _ = ExceptT
72+instance Taggable (ExceptT tag e m) where
73+ type Tag (ExceptT tag e m) = 'Just tag
74+ type Tags' (ExceptT tag e m) = Tags m
7775
78−tagUnwrap :: proxy tag -> ExceptT tag e m a -> Trans.ExceptT e m a
79−tagUnwrap _ (ExceptT a) = a
80−
81−type instance Tags (ExceptT tag r m) = tag ': Tags m
76+instance Tagged (ExceptT tag e m) tag where
77+ type Untagged (ExceptT tag e m) = Trans.ExceptT e m
78+ tagged _ = ExceptT
79+ untagged _ (ExceptT a) = a
8280
8381-- | Constructor for computations in the exception monad transformer.
8482exceptT :: proxy tag -> m (Either e a) -> ExceptT tag e m a
85−exceptT t = tagWrap t . Trans.ExceptT
83+exceptT t = tagged t . Trans.ExceptT
8684
8785-- | Constructor for computations in the exception monad
8886-- (the inverse of 'runExcept').
8987except :: proxy tag -> Either e a -> Except tag e a
90−except t = tagWrap t . Trans.except
88+except t = tagged t . Trans.except
9189
9290-- | Runs an 'ExceptT' and returns either an exception or a normal value.
9391runExceptT :: proxy tag -> ExceptT tag e m a -> m (Either e a)
94−runExceptT t = Trans.runExceptT . tagUnwrap t
92+runExceptT t = Trans.runExceptT . untagged t
9593
9694-- | Transforms the computation inside an 'ExceptT'.
9795--
@@ -101,29 +99,29 @@ mapExceptT
10199 -> (m (Either e a) -> n (Either e' b))
102100 -> ExceptT tag e m a
103101 -> ExceptT tag e' n b
104−mapExceptT t f m = tagWrap t $ Trans.mapExceptT f (coerce m)
102+mapExceptT t f m = tagged t $ Trans.mapExceptT f (coerce m)
105103
106104throw :: Monad m => proxy tag -> e -> ExceptT tag e m a
107−throw t = tagWrap t . Trans.throwE
105+throw t = tagged t . Trans.throwE
108106
109107catch :: Monad m => proxy tag -> ExceptT tag e m a -> (e -> ExceptT tag e m a) -> ExceptT tag e m a
110−catch t m h = tagWrap t $ Trans.catchE (coerce m) (coerce . h)
108+catch t m h = tagged t $ Trans.catchE (coerce m) (coerce . h)
111109
112110-- | Lift a @callCC@ operation to the new monad.
113111liftCallCC :: proxy tag -> Sig.CallCC m (Either e a) (Either e b) -> Sig.CallCC (ExceptT tag e m) a b
114−liftCallCC t callCC f = tagWrap t $ Trans.liftCallCC callCC (coerce f)
112+liftCallCC t callCC f = tagged t $ Trans.liftCallCC callCC (coerce f)
115113
116114-- | Lift a @listen@ operation to the new monad.
117115liftListen :: Monad m => proxy tag -> Sig.Listen w m (Either e a) -> Sig.Listen w (ExceptT tag e m) a
118−liftListen t listen m = tagWrap t $ Trans.liftListen listen (coerce m)
116+liftListen t listen m = tagged t $ Trans.liftListen listen (coerce m)
119117
120118-- | Lift a @pass@ operation to the new monad.
121119liftPass :: Monad m => proxy tag -> Sig.Pass w m (Either e a) -> Sig.Pass w (ExceptT tag e m) a
122−liftPass t pass m = tagWrap t $ Trans.liftPass pass (coerce m)
120+liftPass t pass m = tagged t $ Trans.liftPass pass (coerce m)
123121
124122-- | Lift a @catchE@ operation to the new monad.
125123liftCatch :: proxy tag -> Sig.Catch e m (Either e' a) -> Sig.Catch e (ExceptT tag e' m) a
126−liftCatch t catchE m h = tagWrap t $ Util.liftCatch_ExceptT catchE (coerce m) (coerce h)
124+liftCatch t catchE m h = tagged t $ Util.liftCatch_ExceptT catchE (coerce m) (coerce h)
127125
128126instance Class.MonadCont m => Class.MonadCont (ExceptT tag e m) where
129127 callCC = liftCallCC Proxy Class.callCC
src/Control/Monad/Trans/Ether/Reader.hs+17−19
@@ -24,9 +24,6 @@ module Control.Monad.Trans.Ether.Reader
2424 -- * Lifting other operations
2525 , liftCatch
2626 , liftCallCC
27− -- * Wrapping operations
28− , tagWrap
29− , tagUnwrap
3027 ) where
3128
3229import Data.Proxy (Proxy(Proxy))
@@ -37,7 +34,7 @@ import Control.Monad (MonadPlus)
3734import Control.Monad.Fix (MonadFix)
3835import Control.Monad.Trans.Class (MonadTrans, lift)
3936import Control.Monad.IO.Class (MonadIO)
40−import Control.Ether.Tags (Tags)
37+import Control.Ether.Tags (Taggable(..), Tagged(..), Tags)
4138
4239import qualified Control.Monad.Signatures as Sig
4340import qualified Control.Monad.Trans.Reader as Trans
@@ -65,38 +62,39 @@ newtype ReaderT tag r m a = ReaderT (Trans.ReaderT r m a)
6562 deriving ( Functor, Applicative, Alternative, Monad, MonadPlus
6663 , MonadFix, MonadTrans, MonadIO )
6764
68−tagWrap :: proxy tag -> Trans.ReaderT r m a -> ReaderT tag r m a
69−tagWrap _ = ReaderT
65+instance Taggable (ReaderT tag r m) where
66+ type Tag (ReaderT tag r m) = 'Just tag
67+ type Tags' (ReaderT tag r m) = Tags m
7068
71−tagUnwrap :: proxy tag -> ReaderT tag r m a -> Trans.ReaderT r m a
72−tagUnwrap _ (ReaderT a) = a
73−
74−type instance Tags (ReaderT tag r m) = tag ': Tags m
69+instance Tagged (ReaderT tag r m) tag where
70+ type Untagged (ReaderT tag r m) = Trans.ReaderT r m
71+ tagged _ = ReaderT
72+ untagged _ (ReaderT a) = a
7573
7674-- | Constructor for computations in the reader monad transformer.
7775readerT :: proxy tag -> (r -> m a) -> ReaderT tag r m a
78−readerT t = tagWrap t . Trans.ReaderT
76+readerT t = tagged t . Trans.ReaderT
7977
8078-- | Constructor for computations in the reader monad
8179-- (the inverse of 'runReader').
8280reader :: Monad m => proxy tag -> (r -> a) -> ReaderT tag r m a
83−reader t = tagWrap t . Trans.reader
81+reader t = tagged t . Trans.reader
8482
8583-- | Runs a 'ReaderT' with the given environment
8684-- and returns the vinal value.
8785runReaderT :: proxy tag -> ReaderT tag r m a -> r -> m a
88−runReaderT t = Trans.runReaderT . tagUnwrap t
86+runReaderT t = Trans.runReaderT . untagged t
8987
9088-- | Runs a 'ReaderT' with the given environment
9189-- and returns the vinal value.
9290runReader :: proxy tag -> Reader tag r a -> r -> a
93−runReader t = Trans.runReader . tagUnwrap t
91+runReader t = Trans.runReader . untagged t
9492
9593-- | Transform the computation inside a 'ReaderT'.
9694--
9795-- * @'runReaderT' tag ('mapReaderT' tag f m) = f . 'runReaderT' tag m@
9896mapReaderT :: proxy tag -> (m a -> n b) -> ReaderT tag r m a -> ReaderT tag r n b
99−mapReaderT t f m = tagWrap t $ Trans.mapReaderT f (coerce m)
97+mapReaderT t f m = tagged t $ Trans.mapReaderT f (coerce m)
10098
10199-- | Execute a computation in a modified environment
102100-- (a more general version of 'local').
@@ -109,19 +107,19 @@ withReaderT
109107 -> ReaderT tag r m a
110108 -- ^ Computation to run in the modified environment.
111109 -> ReaderT tag r' m a
112−withReaderT t f m = tagWrap t $ Trans.withReaderT f (coerce m)
110+withReaderT t f m = tagged t $ Trans.withReaderT f (coerce m)
113111
114112-- | Lift a @catchE@ operation to the new monad.
115113liftCatch :: proxy tag -> Sig.Catch e m a -> Sig.Catch e (ReaderT tag r m) a
116−liftCatch t f m h = tagWrap t $ Trans.liftCatch f (coerce m) (coerce h)
114+liftCatch t f m h = tagged t $ Trans.liftCatch f (coerce m) (coerce h)
117115
118116-- | Lift a @callCC@ operation to the new monad.
119117liftCallCC :: proxy tag -> Sig.CallCC m a b -> Sig.CallCC (ReaderT tag r m) a b
120−liftCallCC t callCC f = tagWrap t $ Trans.liftCallCC callCC (coerce f)
118+liftCallCC t callCC f = tagged t $ Trans.liftCallCC callCC (coerce f)
121119
122120-- | Fetch the value of the environment.
123121ask :: Monad m => proxy tag -> ReaderT tag r m r
124−ask t = tagWrap t Trans.ask
122+ask t = tagged t Trans.ask
125123
126124-- | Execute a computation in a modified environment
127125-- (a specialization of 'withReaderT').
src/Control/Monad/Trans/Ether/State.hs+23−24
@@ -29,9 +29,6 @@ module Control.Monad.Trans.Ether.State
2929 , liftCallCC'
3030 , liftListen
3131 , liftPass
32− -- * Wrapping operations
33− , tagWrap
34− , tagUnwrap
3532 ) where
3633
3734import Data.Proxy (Proxy(Proxy))
@@ -42,7 +39,7 @@ import Control.Monad (MonadPlus)
4239import Control.Monad.Fix (MonadFix)
4340import Control.Monad.Trans.Class (MonadTrans, lift)
4441import Control.Monad.IO.Class (MonadIO)
45−import Control.Ether.Tags (Tags)
42+import Control.Ether.Tags (Taggable(..), Tagged(..), Tags)
4643
4744import qualified Control.Monad.Signatures as Sig
4845import qualified Control.Monad.Trans.State.Lazy as Trans
@@ -72,84 +69,86 @@ newtype StateT tag s m a = StateT (Trans.StateT s m a)
7269 deriving ( Functor, Applicative, Alternative, Monad, MonadPlus
7370 , MonadFix, MonadTrans, MonadIO )
7471
75−type instance Tags (StateT tag r m) = tag ': Tags m
7672
77−tagWrap :: proxy tag -> Trans.StateT s m a -> StateT tag s m a
78−tagWrap _ = StateT
73+instance Taggable (StateT tag s m) where
74+ type Tag (StateT tag s m) = 'Just tag
75+ type Tags' (StateT tag s m) = Tags m
7976
80−tagUnwrap :: proxy tag -> StateT tag s m a -> Trans.StateT s m a
81−tagUnwrap _ (StateT a) = a
77+instance Tagged (StateT tag s m) tag where
78+ type Untagged (StateT tag s m) = Trans.StateT s m
79+ tagged _ = StateT
80+ untagged _ (StateT a) = a
8281
8382-- | Constructor for computations in the state monad transformer.
8483stateT :: proxy tag -> (s -> m (a, s)) -> StateT tag s m a
85−stateT t = tagWrap t . Trans.StateT
84+stateT t = tagged t . Trans.StateT
8685
8786-- | Constructor for computations in the state monad
8887-- (the inverse of 'runState').
8988state :: Monad m => proxy tag -> (s -> (a, s)) -> StateT tag s m a
90−state t = tagWrap t . Trans.state
89+state t = tagged t . Trans.state
9190
9291-- | Runs a 'StateT' with the given initial state
9392-- and returns both the final value and the final state.
9493runStateT :: proxy tag -> StateT tag s m a -> s -> m (a, s)
95−runStateT t = Trans.runStateT . tagUnwrap t
94+runStateT t = Trans.runStateT . untagged t
9695
9796-- | Runs a 'StateT' with the given initial state
9897-- and returns the final value, discarding the final state.
9998evalStateT :: Monad m => proxy tag -> StateT tag s m a -> s -> m a
100−evalStateT t = Trans.evalStateT . tagUnwrap t
99+evalStateT t = Trans.evalStateT . untagged t
101100
102101-- | Runs a 'StateT' with the given initial state
103102-- and returns the final state, discarding the final value.
104103execStateT :: Monad m => proxy tag -> StateT tag s m a -> s -> m s
105−execStateT t = Trans.execStateT . tagUnwrap t
104+execStateT t = Trans.execStateT . untagged t
106105
107106-- | Runs a 'State' with the given initial state
108107-- and returns both the final value and the final state.
109108runState :: proxy tag -> State tag s a -> s -> (a, s)
110−runState t = Trans.runState . tagUnwrap t
109+runState t = Trans.runState . untagged t
111110
112111-- | Runs a 'State' with the given initial state
113112-- and returns the final value, discarding the final state.
114113evalState :: proxy tag -> State tag s a -> s -> a
115−evalState t = Trans.evalState . tagUnwrap t
114+evalState t = Trans.evalState . untagged t
116115
117116-- | Runs a 'State' with the given initial state
118117-- and returns the final state, discarding the final value.
119118execState :: proxy tag -> State tag s a -> s -> s
120−execState t = Trans.execState . tagUnwrap t
119+execState t = Trans.execState . untagged t
121120
122121-- | Transform the computation inside a 'StateT'.
123122--
124123-- * @'runStateT' tag ('mapStateT' tag f m) = f . 'runStateT' tag m@
125124mapStateT :: proxy tag -> (m (a, s) -> n (b, s)) -> StateT tag s m a -> StateT tag s n b
126−mapStateT t f m = tagWrap t $ Trans.mapStateT f (coerce m)
125+mapStateT t f m = tagged t $ Trans.mapStateT f (coerce m)
127126
128127-- | Fetch the current value of the state within the monad.
129128get :: Monad m => proxy tag -> StateT tag s m s
130−get t = tagWrap t Trans.get
129+get t = tagged t Trans.get
131130
132131-- | Set the value of the state within the monad.
133132put :: Monad m => proxy tag -> s -> StateT tag s m ()
134−put t = tagWrap t . Trans.put
133+put t = tagged t . Trans.put
135134
136135-- | Lift a @catchE@ operation to the new monad.
137136liftCatch :: proxy tag -> Sig.Catch e m (a, s) -> Sig.Catch e (StateT tag s m) a
138−liftCatch t f m h = tagWrap t $ Trans.liftCatch f (coerce m) (coerce h)
137+liftCatch t f m h = tagged t $ Trans.liftCatch f (coerce m) (coerce h)
139138
140139-- | Lift a @listen@ operation to the new monad.
141140liftListen :: Monad m => proxy tag -> Sig.Listen w m (a, s) -> Sig.Listen w (StateT tag s m) a
142−liftListen t listen m = tagWrap t $ Trans.liftListen listen (coerce m)
141+liftListen t listen m = tagged t $ Trans.liftListen listen (coerce m)
143142
144143-- | In-situ lifting of a @callCC@ operation to the new monad.
145144-- This version uses the current state on entering the continuation.
146145-- It does not satisfy the uniformity property (see "Control.Monad.Signatures").
147146liftCallCC' :: proxy tag -> Sig.CallCC m (a, s) (b, s) -> Sig.CallCC (StateT tag s m) a b
148−liftCallCC' t callCC f = tagWrap t $ Trans.liftCallCC' callCC (coerce f)
147+liftCallCC' t callCC f = tagged t $ Trans.liftCallCC' callCC (coerce f)
149148
150149-- | Lift a @pass@ operation to the new monad.
151150liftPass :: Monad m => proxy tag -> Sig.Pass w m (a,s) -> Sig.Pass w (StateT tag s m) a
152−liftPass t pass m = tagWrap t $ Trans.liftPass pass (coerce m)
151+liftPass t pass m = tagged t $ Trans.liftPass pass (coerce m)
153152
154153-- Instances for mtl classes
155154