c160a313c4d8c1b14f44835357d8bef8c776661b
[darcs-mirrors/transformers.git] / Control / Monad / Trans / Reader.hs
1 {-# LANGUAGE CPP #-}
2 #if __GLASGOW_HASKELL__ >= 702
3 {-# LANGUAGE Safe #-}
4 #endif
5 #if __GLASGOW_HASKELL__ >= 706
6 {-# LANGUAGE PolyKinds #-}
7 #endif
8 #if __GLASGOW_HASKELL__ >= 710
9 {-# LANGUAGE AutoDeriveTypeable #-}
10 #endif
11 -----------------------------------------------------------------------------
12 -- |
13 -- Module : Control.Monad.Trans.Reader
14 -- Copyright : (c) Andy Gill 2001,
15 -- (c) Oregon Graduate Institute of Science and Technology, 2001
16 -- License : BSD-style (see the file LICENSE)
17 --
18 -- Maintainer : R.Paterson@city.ac.uk
19 -- Stability : experimental
20 -- Portability : portable
21 --
22 -- Declaration of the 'ReaderT' monad transformer, which adds a static
23 -- environment to a given monad.
24 --
25 -- If the computation is to modify the stored information, use
26 -- "Control.Monad.Trans.State" instead.
27 -----------------------------------------------------------------------------
28
29 module Control.Monad.Trans.Reader (
30 -- * The Reader monad
31 Reader,
32 reader,
33 runReader,
34 mapReader,
35 withReader,
36 -- * The ReaderT monad transformer
37 ReaderT(..),
38 mapReaderT,
39 withReaderT,
40 -- * Reader operations
41 ask,
42 local,
43 asks,
44 -- * Lifting other operations
45 liftCallCC,
46 liftCatch,
47 ) where
48
49 import Control.Monad.IO.Class
50 import Control.Monad.Signatures
51 import Control.Monad.Trans.Class
52 import Data.Functor.Identity
53
54 import Control.Applicative
55 import Control.Monad
56 #if MIN_VERSION_base(4,9,0)
57 import qualified Control.Monad.Fail as Fail
58 #endif
59 import Control.Monad.Fix
60 #if !(MIN_VERSION_base(4,6,0))
61 import Control.Monad.Instances () -- deprecated from base-4.6
62 #endif
63 #if MIN_VERSION_base(4,4,0)
64 import Control.Monad.Zip (MonadZip(mzipWith))
65 #endif
66 #if MIN_VERSION_base(4,2,0)
67 import Data.Functor(Functor(..))
68 #endif
69
70 -- | The parameterizable reader monad.
71 --
72 -- Computations are functions of a shared environment.
73 --
74 -- The 'return' function ignores the environment, while @>>=@ passes
75 -- the inherited environment to both subcomputations.
76 type Reader r = ReaderT r Identity
77
78 -- | Constructor for computations in the reader monad (equivalent to 'asks').
79 reader :: (Monad m) => (r -> a) -> ReaderT r m a
80 reader f = ReaderT (return . f)
81 {-# INLINE reader #-}
82
83 -- | Runs a @Reader@ and extracts the final value from it.
84 -- (The inverse of 'reader'.)
85 runReader
86 :: Reader r a -- ^ A @Reader@ to run.
87 -> r -- ^ An initial environment.
88 -> a
89 runReader m = runIdentity . runReaderT m
90 {-# INLINE runReader #-}
91
92 -- | Transform the value returned by a @Reader@.
93 --
94 -- * @'runReader' ('mapReader' f m) = f . 'runReader' m@
95 mapReader :: (a -> b) -> Reader r a -> Reader r b
96 mapReader f = mapReaderT (Identity . f . runIdentity)
97 {-# INLINE mapReader #-}
98
99 -- | Execute a computation in a modified environment
100 -- (a specialization of 'withReaderT').
101 --
102 -- * @'runReader' ('withReader' f m) = 'runReader' m . f@
103 withReader
104 :: (r' -> r) -- ^ The function to modify the environment.
105 -> Reader r a -- ^ Computation to run in the modified environment.
106 -> Reader r' a
107 withReader = withReaderT
108 {-# INLINE withReader #-}
109
110 -- | The reader monad transformer,
111 -- which adds a read-only environment to the given monad.
112 --
113 -- The 'return' function ignores the environment, while @>>=@ passes
114 -- the inherited environment to both subcomputations.
115 newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
116
117 -- | Transform the computation inside a @ReaderT@.
118 --
119 -- * @'runReaderT' ('mapReaderT' f m) = f . 'runReaderT' m@
120 mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
121 mapReaderT f m = ReaderT $ f . runReaderT m
122 {-# INLINE mapReaderT #-}
123
124 -- | Execute a computation in a modified environment
125 -- (a more general version of 'local').
126 --
127 -- * @'runReaderT' ('withReaderT' f m) = 'runReaderT' m . f@
128 withReaderT
129 :: (r' -> r) -- ^ The function to modify the environment.
130 -> ReaderT r m a -- ^ Computation to run in the modified environment.
131 -> ReaderT r' m a
132 withReaderT f m = ReaderT $ runReaderT m . f
133 {-# INLINE withReaderT #-}
134
135 instance (Functor m) => Functor (ReaderT r m) where
136 fmap f = mapReaderT (fmap f)
137 {-# INLINE fmap #-}
138 #if MIN_VERSION_base(4,2,0)
139 x <$ v = mapReaderT (x <$) v
140 {-# INLINE (<$) #-}
141 #endif
142
143 instance (Applicative m) => Applicative (ReaderT r m) where
144 pure = liftReaderT . pure
145 {-# INLINE pure #-}
146 f <*> v = ReaderT $ \ r -> runReaderT f r <*> runReaderT v r
147 {-# INLINE (<*>) #-}
148 #if MIN_VERSION_base(4,2,0)
149 u *> v = ReaderT $ \ r -> runReaderT u r *> runReaderT v r
150 {-# INLINE (*>) #-}
151 u <* v = ReaderT $ \ r -> runReaderT u r <* runReaderT v r
152 {-# INLINE (<*) #-}
153 #endif
154
155 instance (Alternative m) => Alternative (ReaderT r m) where
156 empty = liftReaderT empty
157 {-# INLINE empty #-}
158 m <|> n = ReaderT $ \ r -> runReaderT m r <|> runReaderT n r
159 {-# INLINE (<|>) #-}
160
161 instance (Monad m) => Monad (ReaderT r m) where
162 #if !(MIN_VERSION_base(4,8,0))
163 return = lift . return
164 {-# INLINE return #-}
165 #endif
166 m >>= k = ReaderT $ \ r -> do
167 a <- runReaderT m r
168 runReaderT (k a) r
169 {-# INLINE (>>=) #-}
170 m >> k = ReaderT $ \ r -> runReaderT m r >> runReaderT k r
171 {-# INLINE (>>) #-}
172 fail msg = lift (fail msg)
173 {-# INLINE fail #-}
174
175 #if MIN_VERSION_base(4,9,0)
176 instance (Fail.MonadFail m) => Fail.MonadFail (ReaderT r m) where
177 fail msg = lift (Fail.fail msg)
178 {-# INLINE fail #-}
179 #endif
180
181 instance (MonadPlus m) => MonadPlus (ReaderT r m) where
182 mzero = lift mzero
183 {-# INLINE mzero #-}
184 m `mplus` n = ReaderT $ \ r -> runReaderT m r `mplus` runReaderT n r
185 {-# INLINE mplus #-}
186
187 instance (MonadFix m) => MonadFix (ReaderT r m) where
188 mfix f = ReaderT $ \ r -> mfix $ \ a -> runReaderT (f a) r
189 {-# INLINE mfix #-}
190
191 instance MonadTrans (ReaderT r) where
192 lift = liftReaderT
193 {-# INLINE lift #-}
194
195 instance (MonadIO m) => MonadIO (ReaderT r m) where
196 liftIO = lift . liftIO
197 {-# INLINE liftIO #-}
198
199 #if MIN_VERSION_base(4,4,0)
200 instance (MonadZip m) => MonadZip (ReaderT r m) where
201 mzipWith f (ReaderT m) (ReaderT n) = ReaderT $ \ a ->
202 mzipWith f (m a) (n a)
203 {-# INLINE mzipWith #-}
204 #endif
205
206 liftReaderT :: m a -> ReaderT r m a
207 liftReaderT m = ReaderT (const m)
208 {-# INLINE liftReaderT #-}
209
210 -- | Fetch the value of the environment.
211 ask :: (Monad m) => ReaderT r m r
212 ask = ReaderT return
213 {-# INLINE ask #-}
214
215 -- | Execute a computation in a modified environment
216 -- (a specialization of 'withReaderT').
217 --
218 -- * @'runReaderT' ('local' f m) = 'runReaderT' m . f@
219 local
220 :: (r -> r) -- ^ The function to modify the environment.
221 -> ReaderT r m a -- ^ Computation to run in the modified environment.
222 -> ReaderT r m a
223 local = withReaderT
224 {-# INLINE local #-}
225
226 -- | Retrieve a function of the current environment.
227 --
228 -- * @'asks' f = 'liftM' f 'ask'@
229 asks :: (Monad m)
230 => (r -> a) -- ^ The selector function to apply to the environment.
231 -> ReaderT r m a
232 asks f = ReaderT (return . f)
233 {-# INLINE asks #-}
234
235 -- | Lift a @callCC@ operation to the new monad.
236 liftCallCC :: CallCC m a b -> CallCC (ReaderT r m) a b
237 liftCallCC callCC f = ReaderT $ \ r ->
238 callCC $ \ c ->
239 runReaderT (f (ReaderT . const . c)) r
240 {-# INLINE liftCallCC #-}
241
242 -- | Lift a @catchE@ operation to the new monad.
243 liftCatch :: Catch e m a -> Catch e (ReaderT r m) a
244 liftCatch f m h =
245 ReaderT $ \ r -> f (runReaderT m r) (\ e -> runReaderT (h e) r)
246 {-# INLINE liftCatch #-}