@@ -1,57 +1,11 @@
1−{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-}
3{-# LANGUAGE DeriveGeneric #-}
1{-# LANGUAGE DeriveGeneric #-}
4−{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE UndecidableInstances #-}
4{-# LANGUAGE UndecidableInstances #-}
7−{-# LANGUAGE DataKinds #-}
5+{-# LANGUAGE ConstraintKinds #-}
8−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6+{-# LANGUAGE TypeFamilies #-}
12−Type-level machinery to manipulate constraints on the monad
15−Out of the box it provides the following dispatch strategies:
17−* 'tagAttach' to use functions defined using untagged monad classes
18− as if they were defined using tagged ones.
20−* 'tagReplace' to use functions defined using one tag
21− as if they were defined using another one.
23−> import qualified Control.Monad.State as T
24−> import Control.Ether.TH (ethereal)
25−> import Control.Monad.Ether.State (MonadState)
26−> import Control.Monad.Trans.Ether.Dispatch (tagAttach, tagDispatch)
28−> ethereal "Foo" "foo"
29−> ethereal "Bar" "bar"
31−> f :: T.MonadState Int m => m String
34−> g :: MonadState Foo Int m => m String
37−> h :: MonadState Bar Int m => m String
38−> h = tagReplace foo bar g
42−module Control.Monad.Trans.Ether.Dispatch
8+module Control.Monad.Trans.Ether.Dispatch where
44− -- * The DispatchT monad transformer
49− -- * Dispatch types and functions
56import Control.Applicative
10import Control.Applicative
57import Control.Monad (MonadPlus)
11import Control.Monad (MonadPlus)
@@ -63,7 +17,6 @@ import Control.Monad.Catch (MonadThrow, MonadCatch, MonadMask)
64import qualified Control.Monad.Base as MB
18import qualified Control.Monad.Base as MB
65import qualified Control.Monad.Trans.Control as MC
19import qualified Control.Monad.Trans.Control as MC
66−import qualified Control.Monad.Trans.Identity as Trans
68import qualified Control.Monad.Trans.Lift.StT as Lift
21import qualified Control.Monad.Trans.Lift.StT as Lift
69import qualified Control.Monad.Trans.Lift.Local as Lift
22import qualified Control.Monad.Trans.Lift.Local as Lift
@@ -72,16 +25,6 @@ import qualified Control.Monad.Trans.Lift.Listen as Lift
72import qualified Control.Monad.Trans.Lift.Pass as Lift
25import qualified Control.Monad.Trans.Lift.Pass as Lift
73import qualified Control.Monad.Trans.Lift.CallCC as Lift
26import qualified Control.Monad.Trans.Lift.CallCC as Lift
75−import Control.Monad.Ether.Reader.Class
76−import Control.Monad.Ether.State.Class
77−import Control.Monad.Ether.Except.Class
78−import Control.Monad.Ether.Writer.Class
80−import Control.Monad.Ether.Reader as A
81−import Control.Monad.Ether.State.Common as A
82−import Control.Monad.Ether.Except as A
83−import Control.Monad.Ether.Writer as A
85import qualified Control.Monad.Cont.Class as Class
28import qualified Control.Monad.Cont.Class as Class
86import qualified Control.Monad.Reader.Class as Class
29import qualified Control.Monad.Reader.Class as Class
87import qualified Control.Monad.State.Class as Class
30import qualified Control.Monad.State.Class as Class
@@ -91,84 +34,75 @@ import qualified Control.Monad.Error.Class as Class
91import GHC.Generics (Generic)
34import GHC.Generics (Generic)
92import Data.Coerce (coerce)
35import Data.Coerce (coerce)
94−-- | Wrap a monad to change its tags. Under the hood this is
37+newtype Dispatch dp trans m a = Dispatch (trans m a)
95−-- simply 'Trans.IdentityT', all the work is happening on the type level.
96−newtype DispatchT dp m a = DispatchT (Trans.IdentityT m a)
99 , Functor, Applicative, Alternative, Monad, MonadPlus
40 , Functor, Applicative, Alternative, Monad, MonadPlus
100 , MonadFix, MonadTrans, MonadIO, MFunctor, MMonad
41 , MonadFix, MonadTrans, MonadIO, MFunctor, MMonad
101 , MonadThrow, MonadCatch, MonadMask )
42 , MonadThrow, MonadCatch, MonadMask )
103−-- | Type-restricted 'coerce'.
104−pack :: forall dp m a . Trans.IdentityT m a -> DispatchT dp m a
44+pack :: forall dp trans m a . trans m a -> Dispatch dp trans m a
105pack = coerce
45pack = coerce
106{-# INLINE pack #-}
46{-# INLINE pack #-}
108−-- | Type-restricted 'coerce'.
109−unpack :: forall dp m a . DispatchT dp m a -> Trans.IdentityT m a
48+unpack :: forall dp trans m a . Dispatch dp trans m a -> trans m a
110unpack = coerce
49unpack = coerce
111{-# INLINE unpack #-}
50{-# INLINE unpack #-}
113−-- | Type-restricted 'coerce'.
52+repack :: forall dp dp' trans m a . Dispatch dp trans m a -> Dispatch dp' trans m a
114−dispatchT :: forall dp m a . m a -> DispatchT dp m a
116−{-# INLINE dispatchT #-}
118−-- | Type-restricted 'coerce'.
119−runDispatchT :: forall dp m a . DispatchT dp m a -> m a
120−runDispatchT = coerce
53+repack = coerce
121−{-# INLINE runDispatchT #-}
54+{-# INLINE repack #-}
123−-- | Type-restricted 'coerce'.
56+instance
124−redispatch :: forall dp dp' m a . DispatchT dp m a -> DispatchT dp' m a
57+ ( MB.MonadBase b m
125−redispatch = coerce
58+ , MonadTrans trans
126−{-# INLINE redispatch #-}
59+ , Monad (trans m)
127−
60+ ) => MB.MonadBase b (Dispatch dp trans m)
128−instance MB.MonadBase b m => MB.MonadBase b (DispatchT dp m) where
61+ where
129− liftBase = MB.liftBaseDefault
62+ liftBase = MB.liftBaseDefault
131−instance MC.MonadTransControl (DispatchT dp) where
132− type StT (DispatchT dp) a = MC.StT Trans.IdentityT a
133− liftWith = MC.defaultLiftWith pack unpack
134− restoreT = MC.defaultRestoreT pack
136−instance MC.MonadBaseControl b m => MC.MonadBaseControl b (DispatchT dp m) where
64+instance
137− type StM (DispatchT dp m) a = MC.ComposeSt (DispatchT dp) m a
65+ ( MC.MonadTransControl trans
138− liftBaseWith = MC.defaultLiftBaseWith
66+ ) => MC.MonadTransControl (Dispatch dp trans)
139− restoreM = MC.defaultRestoreM
67+ where
68+ type StT (Dispatch dp trans) a = MC.StT trans a
69+ liftWith = MC.defaultLiftWith pack unpack
70+ restoreT = MC.defaultRestoreT pack
141−type instance Lift.StT (DispatchT dp) a = MC.StT (DispatchT dp) a
72+type instance Lift.StT (Dispatch dp trans) a = Lift.StT trans a
143−instance Lift.LiftLocal (DispatchT dp) where
74+instance Lift.LiftLocal trans => Lift.LiftLocal (Dispatch dp trans) where
144 liftLocal = Lift.defaultLiftLocal pack unpack
75 liftLocal = Lift.defaultLiftLocal pack unpack
146−instance Lift.LiftCatch (DispatchT dp) where
77+instance Lift.LiftCatch trans => Lift.LiftCatch (Dispatch dp trans) where
147 liftCatch = Lift.defaultLiftCatch pack unpack
78 liftCatch = Lift.defaultLiftCatch pack unpack
149−instance Lift.LiftListen (DispatchT dp) where
80+instance Lift.LiftListen trans => Lift.LiftListen (Dispatch dp trans) where
150 liftListen = Lift.defaultLiftListen pack unpack
81 liftListen = Lift.defaultLiftListen pack unpack
152−instance Lift.LiftPass (DispatchT dp) where
83+instance Lift.LiftPass trans => Lift.LiftPass (Dispatch dp trans) where
153 liftPass = Lift.defaultLiftPass pack unpack
84 liftPass = Lift.defaultLiftPass pack unpack
155−instance Lift.LiftCallCC (DispatchT dp) where
86+instance Lift.LiftCallCC trans => Lift.LiftCallCC (Dispatch dp trans) where
156 liftCallCC = Lift.defaultLiftCallCC pack unpack
87 liftCallCC = Lift.defaultLiftCallCC pack unpack
157 liftCallCC' = Lift.defaultLiftCallCC' pack unpack
88 liftCallCC' = Lift.defaultLiftCallCC' pack unpack
159-- Instances for mtl classes
91-- Instances for mtl classes
161instance {-# OVERLAPPABLE #-}
93instance {-# OVERLAPPABLE #-}
162 ( Class.MonadCont m
94 ( Class.MonadCont m
95+ , Lift.LiftCallCC trans
163− , Monad m
96+ , Monad (trans m)
164− ) => Class.MonadCont (DispatchT dp m)
97+ ) => Class.MonadCont (Dispatch dp trans m)
166 callCC = Lift.liftCallCC' Class.callCC
99 callCC = Lift.liftCallCC' Class.callCC
168instance {-# OVERLAPPABLE #-}
101instance {-# OVERLAPPABLE #-}
169 ( Class.MonadReader r m
102 ( Class.MonadReader r m
103+ , Lift.LiftLocal trans
170− , Monad m
104+ , Monad (trans m)
171− ) => Class.MonadReader r (DispatchT dp m)
105+ ) => Class.MonadReader r (Dispatch dp trans m)
173 ask = lift Class.ask
107 ask = lift Class.ask
174 local = Lift.liftLocal Class.ask Class.local
108 local = Lift.liftLocal Class.ask Class.local
@@ -176,8 +110,9 @@ instance {-# OVERLAPPABLE #-}
177instance {-# OVERLAPPABLE #-}
111instance {-# OVERLAPPABLE #-}
178 ( Class.MonadState s m
112 ( Class.MonadState s m
179− , Monad m
114+ , Monad (trans m)
180− ) => Class.MonadState s (DispatchT dp m)
115+ ) => Class.MonadState s (Dispatch dp trans m)
182 get = lift Class.get
117 get = lift Class.get
183 put = lift . Class.put
118 put = lift . Class.put
@@ -185,8 +120,10 @@ instance {-# OVERLAPPABLE #-}
186instance {-# OVERLAPPABLE #-}
121instance {-# OVERLAPPABLE #-}
187 ( Class.MonadWriter w m
122 ( Class.MonadWriter w m
123+ , Lift.LiftListen trans
124+ , Lift.LiftPass trans
188− , Monad m
125+ , Monad (trans m)
189− ) => Class.MonadWriter w (DispatchT dp m)
126+ ) => Class.MonadWriter w (Dispatch dp trans m)
191 writer = lift . Class.writer
128 writer = lift . Class.writer
192 tell = lift . Class.tell
129 tell = lift . Class.tell
@@ -195,76 +132,9 @@ instance {-# OVERLAPPABLE #-}
196instance {-# OVERLAPPABLE #-}
133instance {-# OVERLAPPABLE #-}
197 ( Class.MonadError e m
134 ( Class.MonadError e m
135+ , Lift.LiftCatch trans
198− , Monad m
136+ , Monad (trans m)
199− ) => Class.MonadError e (DispatchT dp m)
137+ ) => Class.MonadError e (Dispatch dp trans m)
201 throwError = lift . Class.throwError
139 throwError = lift . Class.throwError
202 catchError = Lift.liftCatch Class.catchError
140 catchError = Lift.liftCatch Class.catchError
207−-- | Encode type-level information for 'tagAttach'.
208−data K_TagAttach t = TagAttach t
210−type DispatchTagAttachT t = DispatchT (TagAttach t)
212−-- | Attach a tag to untagged transformers.
213−tagAttach :: forall tag m a . DispatchTagAttachT tag m a -> m a
214−tagAttach = runDispatchT
216−instance MonadReader tag r m
217− => Class.MonadReader r (DispatchTagAttachT tag m) where
218− ask = Lift.lift (A.ask @tag)
219− local = Lift.liftLocal (A.ask @tag) (A.local @tag)
221−instance MonadState tag s m
222− => Class.MonadState s (DispatchTagAttachT tag m) where
223− get = Lift.lift (A.get @tag)
224− put = Lift.lift . A.put @tag
226−instance MonadExcept tag e m
227− => Class.MonadError e (DispatchTagAttachT tag m) where
228− throwError = Lift.lift . A.throw @tag
229− catchError = Lift.liftCatch (A.catch @tag)
231−instance MonadWriter tag w m
232− => Class.MonadWriter w (DispatchTagAttachT tag m) where
233− writer = Lift.lift . A.writer @tag
234− tell = Lift.lift . A.tell @tag
235− listen = Lift.liftListen (A.listen @tag)
236− pass = Lift.liftPass (A.pass @tag)
241−-- | Encode type-level information for 'tagReplace'.
242−data K_TagReplace tOld tNew = TagReplace tOld tNew
244−type DispatchTagReplaceT tOld tNew = DispatchT (TagReplace tOld tNew)
246−-- | Replace a tag with another tag.
247−tagReplace :: forall tOld tNew m a . DispatchTagReplaceT tOld tNew m a -> m a
248−tagReplace = runDispatchT
250−instance MonadReader tNew r m
251− => MonadReader tOld r (DispatchTagReplaceT tOld tNew m) where
252− ask _ = Lift.lift (A.ask @tNew)
253− local _ = Lift.liftLocal (A.ask @tNew) (A.local @tNew)
255−instance MonadState tNew s m
256− => MonadState tOld s (DispatchTagReplaceT tOld tNew m) where
257− get _ = Lift.lift (A.get @tNew)
258− put _ = Lift.lift . A.put @tNew
260−instance MonadExcept tNew e m
261− => MonadExcept tOld e (DispatchTagReplaceT tOld tNew m) where
262− throw _ = Lift.lift . A.throw @tNew
263− catch _ = Lift.liftCatch (A.catch @tNew)
265−instance MonadWriter tNew w m
266− => MonadWriter tOld w (DispatchTagReplaceT tOld tNew m) where
267− writer _ = Lift.lift . A.writer @tNew
268− tell _ = Lift.lift . A.tell @tNew
269− listen _ = Lift.liftListen (A.listen @tNew)
270− pass _ = Lift.liftPass (A.pass @tNew)