diff options
author | joe <joe@jerkface.net> | 2014-02-12 20:35:52 -0500 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-02-12 20:35:52 -0500 |
commit | 7ccaa169bc2309df7df2db118dd646177867f2b0 (patch) | |
tree | 82b5e8f7e744f7d919b49ebcb0b0654def7d7d32 /Data/Conduit | |
parent | 5ad7794bcd86a0049d1e62cae2f04f6088a0ef34 (diff) |
Reply to pings with pongs.
Diffstat (limited to 'Data/Conduit')
-rw-r--r-- | Data/Conduit/Lift.hs | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/Data/Conduit/Lift.hs b/Data/Conduit/Lift.hs new file mode 100644 index 00000000..341fce53 --- /dev/null +++ b/Data/Conduit/Lift.hs | |||
@@ -0,0 +1,526 @@ | |||
1 | |||
2 | |||
3 | {-# LANGUAGE RankNTypes #-} | ||
4 | -- | Allow monad transformers to be run/eval/exec in a section of conduit | ||
5 | -- rather then needing to run across the whole conduit. The circumvents many | ||
6 | -- of the problems with breaking the monad transformer laws. For more | ||
7 | -- information, see the announcement blog post: | ||
8 | -- <http://www.yesodweb.com/blog/2014/01/conduit-transformer-exception> | ||
9 | -- | ||
10 | -- This module was added in conduit 1.0.11. | ||
11 | module Data.Conduit.Lift ( | ||
12 | -- * ErrorT | ||
13 | errorC, | ||
14 | runErrorC, | ||
15 | catchErrorC, | ||
16 | -- liftCatchError, | ||
17 | |||
18 | -- * MaybeT | ||
19 | maybeC, | ||
20 | runMaybeC, | ||
21 | |||
22 | -- * ReaderT | ||
23 | readerC, | ||
24 | runReaderC, | ||
25 | |||
26 | -- * StateT | ||
27 | stateC, | ||
28 | runStateC, | ||
29 | evalStateC, | ||
30 | execStateC, | ||
31 | |||
32 | -- ** Strict | ||
33 | stateSC, | ||
34 | runStateSC, | ||
35 | evalStateSC, | ||
36 | execStateSC, | ||
37 | |||
38 | -- * WriterT | ||
39 | writerC, | ||
40 | runWriterC, | ||
41 | execWriterC, | ||
42 | |||
43 | -- ** Strict | ||
44 | writerSC, | ||
45 | runWriterSC, | ||
46 | execWriterSC, | ||
47 | |||
48 | -- * RWST | ||
49 | rwsC, | ||
50 | runRWSC, | ||
51 | evalRWSC, | ||
52 | execRWSC, | ||
53 | |||
54 | -- ** Strict | ||
55 | rwsSC, | ||
56 | runRWSSC, | ||
57 | evalRWSSC, | ||
58 | execRWSSC, | ||
59 | |||
60 | -- * Utilities | ||
61 | |||
62 | distribute | ||
63 | ) where | ||
64 | |||
65 | import Data.Conduit | ||
66 | import Data.Conduit.Internal (ConduitM (..), Pipe (..)) | ||
67 | |||
68 | import Control.Monad.Morph (hoist, lift, MFunctor(..), ) | ||
69 | import Control.Monad.Trans.Class (MonadTrans(..)) | ||
70 | |||
71 | import Data.Monoid (Monoid(..)) | ||
72 | |||
73 | |||
74 | import qualified Control.Monad.Trans.Error as E | ||
75 | import qualified Control.Monad.Trans.Maybe as M | ||
76 | import qualified Control.Monad.Trans.Reader as R | ||
77 | |||
78 | import qualified Control.Monad.Trans.State.Strict as SS | ||
79 | import qualified Control.Monad.Trans.Writer.Strict as WS | ||
80 | import qualified Control.Monad.Trans.RWS.Strict as RWSS | ||
81 | |||
82 | import qualified Control.Monad.Trans.State.Lazy as SL | ||
83 | import qualified Control.Monad.Trans.Writer.Lazy as WL | ||
84 | import qualified Control.Monad.Trans.RWS.Lazy as RWSL | ||
85 | |||
86 | |||
87 | catAwaitLifted | ||
88 | :: (Monad (t (ConduitM o1 o m)), Monad m, MonadTrans t) => | ||
89 | ConduitM i o1 (t (ConduitM o1 o m)) () | ||
90 | catAwaitLifted = go | ||
91 | where | ||
92 | go = do | ||
93 | x <- lift . lift $ await | ||
94 | case x of | ||
95 | Nothing -> return () | ||
96 | Just x2 -> do | ||
97 | yield x2 | ||
98 | go | ||
99 | |||
100 | catYieldLifted | ||
101 | :: (Monad (t (ConduitM i o1 m)), Monad m, MonadTrans t) => | ||
102 | ConduitM o1 o (t (ConduitM i o1 m)) () | ||
103 | catYieldLifted = go | ||
104 | where | ||
105 | go = do | ||
106 | x <- await | ||
107 | case x of | ||
108 | Nothing -> return () | ||
109 | Just x2 -> do | ||
110 | lift . lift $ yield x2 | ||
111 | go | ||
112 | |||
113 | |||
114 | distribute | ||
115 | :: (Monad (t (ConduitM b o m)), Monad m, Monad (t m), MonadTrans t, | ||
116 | MFunctor t) => | ||
117 | ConduitM b o (t m) () -> t (ConduitM b o m) () | ||
118 | distribute p = catAwaitLifted =$= hoist (hoist lift) p $$ catYieldLifted | ||
119 | |||
120 | -- | Run 'E.ErrorT' in the base monad | ||
121 | -- | ||
122 | -- Since 1.0.11 | ||
123 | errorC | ||
124 | :: (Monad m, Monad (t (E.ErrorT e m)), MonadTrans t, E.Error e, | ||
125 | MFunctor t) => | ||
126 | t m (Either e b) -> t (E.ErrorT e m) b | ||
127 | errorC p = do | ||
128 | x <- hoist lift p | ||
129 | lift $ E.ErrorT (return x) | ||
130 | |||
131 | -- | Run 'E.ErrorT' in the base monad | ||
132 | -- | ||
133 | -- Since 1.0.11 | ||
134 | runErrorC | ||
135 | :: (Monad m, E.Error e) => | ||
136 | ConduitM i o (E.ErrorT e m) r -> ConduitM i o m (Either e r) | ||
137 | runErrorC = | ||
138 | ConduitM . go . unConduitM | ||
139 | where | ||
140 | go (Done r) = Done (Right r) | ||
141 | go (PipeM mp) = PipeM $ do | ||
142 | eres <- E.runErrorT mp | ||
143 | return $ case eres of | ||
144 | Left e -> Done $ Left e | ||
145 | Right p -> go p | ||
146 | go (Leftover p i) = Leftover (go p) i | ||
147 | go (HaveOutput p f o) = HaveOutput (go p) (E.runErrorT f >> return ()) o | ||
148 | go (NeedInput x y) = NeedInput (go . x) (go . y) | ||
149 | {-# INLINABLE runErrorC #-} | ||
150 | |||
151 | -- | Catch an error in the base monad | ||
152 | -- | ||
153 | -- Since 1.0.11 | ||
154 | catchErrorC | ||
155 | :: (Monad m, E.Error e) => | ||
156 | ConduitM i o (E.ErrorT e m) r | ||
157 | -> (e -> ConduitM i o (E.ErrorT e m) r) | ||
158 | -> ConduitM i o (E.ErrorT e m) r | ||
159 | catchErrorC c0 h = | ||
160 | ConduitM $ go $ unConduitM c0 | ||
161 | where | ||
162 | go (Done r) = Done r | ||
163 | go (PipeM mp) = PipeM $ do | ||
164 | eres <- lift $ E.runErrorT mp | ||
165 | return $ case eres of | ||
166 | Left e -> unConduitM $ h e | ||
167 | Right p -> go p | ||
168 | go (Leftover p i) = Leftover (go p) i | ||
169 | go (HaveOutput p f o) = HaveOutput (go p) f o | ||
170 | go (NeedInput x y) = NeedInput (go . x) (go . y) | ||
171 | {-# INLINABLE catchErrorC #-} | ||
172 | |||
173 | -- | Wrap the base monad in 'M.MaybeT' | ||
174 | -- | ||
175 | -- Since 1.0.11 | ||
176 | maybeC | ||
177 | :: (Monad m, Monad (t (M.MaybeT m)), | ||
178 | MonadTrans t, | ||
179 | MFunctor t) => | ||
180 | t m (Maybe b) -> t (M.MaybeT m) b | ||
181 | maybeC p = do | ||
182 | x <- hoist lift p | ||
183 | lift $ M.MaybeT (return x) | ||
184 | {-# INLINABLE maybeC #-} | ||
185 | |||
186 | -- | Run 'M.MaybeT' in the base monad | ||
187 | -- | ||
188 | -- Since 1.0.11 | ||
189 | runMaybeC | ||
190 | :: Monad m => | ||
191 | ConduitM i o (M.MaybeT m) r -> ConduitM i o m (Maybe r) | ||
192 | runMaybeC = | ||
193 | ConduitM . go . unConduitM | ||
194 | where | ||
195 | go (Done r) = Done (Just r) | ||
196 | go (PipeM mp) = PipeM $ do | ||
197 | mres <- M.runMaybeT mp | ||
198 | return $ case mres of | ||
199 | Nothing -> Done Nothing | ||
200 | Just p -> go p | ||
201 | go (Leftover p i) = Leftover (go p) i | ||
202 | go (HaveOutput p c o) = HaveOutput (go p) (M.runMaybeT c >> return ()) o | ||
203 | go (NeedInput x y) = NeedInput (go . x) (go . y) | ||
204 | {-# INLINABLE runMaybeC #-} | ||
205 | |||
206 | -- | Wrap the base monad in 'R.ReaderT' | ||
207 | -- | ||
208 | -- Since 1.0.11 | ||
209 | readerC | ||
210 | :: (Monad m, Monad (t1 (R.ReaderT t m)), | ||
211 | MonadTrans t1, | ||
212 | MFunctor t1) => | ||
213 | (t -> t1 m b) -> t1 (R.ReaderT t m) b | ||
214 | readerC k = do | ||
215 | i <- lift R.ask | ||
216 | hoist lift (k i) | ||
217 | {-# INLINABLE readerC #-} | ||
218 | |||
219 | -- | Run 'R.ReaderT' in the base monad | ||
220 | -- | ||
221 | -- Since 1.0.11 | ||
222 | runReaderC | ||
223 | :: Monad m => | ||
224 | r -> ConduitM i o (R.ReaderT r m) res -> ConduitM i o m res | ||
225 | runReaderC r = hoist (`R.runReaderT` r) | ||
226 | {-# INLINABLE runReaderC #-} | ||
227 | |||
228 | |||
229 | -- | Wrap the base monad in 'SL.StateT' | ||
230 | -- | ||
231 | -- Since 1.0.11 | ||
232 | stateC | ||
233 | :: (Monad m, Monad (t1 (SL.StateT t m)), | ||
234 | MonadTrans t1, | ||
235 | MFunctor t1) => | ||
236 | (t -> t1 m (b, t)) -> t1 (SL.StateT t m) b | ||
237 | stateC k = do | ||
238 | s <- lift SL.get | ||
239 | (r, s') <- hoist lift (k s) | ||
240 | lift (SL.put s') | ||
241 | return r | ||
242 | {-# INLINABLE stateC #-} | ||
243 | |||
244 | thread :: Monad m | ||
245 | => (r -> s -> res) | ||
246 | -> (forall a. t m a -> s -> m (a, s)) | ||
247 | -> s | ||
248 | -> ConduitM i o (t m) r | ||
249 | -> ConduitM i o m res | ||
250 | thread toRes runM s0 = | ||
251 | ConduitM . go s0 . unConduitM | ||
252 | where | ||
253 | go s (Done r) = Done (toRes r s) | ||
254 | go s (PipeM mp) = PipeM $ do | ||
255 | (p, s') <- runM mp s | ||
256 | return $ go s' p | ||
257 | go s (Leftover p i) = Leftover (go s p) i | ||
258 | go s (NeedInput x y) = NeedInput (go s . x) (go s . y) | ||
259 | go s (HaveOutput p f o) = HaveOutput (go s p) (runM f s >> return ()) o | ||
260 | {-# INLINABLE thread #-} | ||
261 | |||
262 | -- | Run 'SL.StateT' in the base monad | ||
263 | -- | ||
264 | -- Since 1.0.11 | ||
265 | runStateC | ||
266 | :: Monad m => | ||
267 | s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m (r, s) | ||
268 | runStateC = thread (,) SL.runStateT | ||
269 | {-# INLINABLE runStateC #-} | ||
270 | |||
271 | -- | Evaluate 'SL.StateT' in the base monad | ||
272 | -- | ||
273 | -- Since 1.0.11 | ||
274 | evalStateC | ||
275 | :: Monad m => | ||
276 | s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m r | ||
277 | evalStateC s p = fmap fst $ runStateC s p | ||
278 | {-# INLINABLE evalStateC #-} | ||
279 | |||
280 | -- | Execute 'SL.StateT' in the base monad | ||
281 | -- | ||
282 | -- Since 1.0.11 | ||
283 | execStateC | ||
284 | :: Monad m => | ||
285 | s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m s | ||
286 | execStateC s p = fmap snd $ runStateC s p | ||
287 | {-# INLINABLE execStateC #-} | ||
288 | |||
289 | |||
290 | -- | Wrap the base monad in 'SS.StateT' | ||
291 | -- | ||
292 | -- Since 1.0.11 | ||
293 | stateSC | ||
294 | :: (Monad m, Monad (t1 (SS.StateT t m)), | ||
295 | MonadTrans t1, | ||
296 | MFunctor t1) => | ||
297 | (t -> t1 m (b, t)) -> t1 (SS.StateT t m) b | ||
298 | stateSC k = do | ||
299 | s <- lift SS.get | ||
300 | (r, s') <- hoist lift (k s) | ||
301 | lift (SS.put s') | ||
302 | return r | ||
303 | {-# INLINABLE stateSC #-} | ||
304 | |||
305 | -- | Run 'SS.StateT' in the base monad | ||
306 | -- | ||
307 | -- Since 1.0.11 | ||
308 | runStateSC | ||
309 | :: Monad m => | ||
310 | s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m (r, s) | ||
311 | runStateSC = thread (,) SS.runStateT | ||
312 | {-# INLINABLE runStateSC #-} | ||
313 | |||
314 | -- | Evaluate 'SS.StateT' in the base monad | ||
315 | -- | ||
316 | -- Since 1.0.11 | ||
317 | evalStateSC | ||
318 | :: Monad m => | ||
319 | s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m r | ||
320 | evalStateSC s p = fmap fst $ runStateSC s p | ||
321 | {-# INLINABLE evalStateSC #-} | ||
322 | |||
323 | -- | Execute 'SS.StateT' in the base monad | ||
324 | -- | ||
325 | -- Since 1.0.11 | ||
326 | execStateSC | ||
327 | :: Monad m => | ||
328 | s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m s | ||
329 | execStateSC s p = fmap snd $ runStateSC s p | ||
330 | {-# INLINABLE execStateSC #-} | ||
331 | |||
332 | |||
333 | -- | Wrap the base monad in 'WL.WriterT' | ||
334 | -- | ||
335 | -- Since 1.0.11 | ||
336 | writerC | ||
337 | :: (Monad m, Monad (t (WL.WriterT w m)), MonadTrans t, Monoid w, | ||
338 | MFunctor t) => | ||
339 | t m (b, w) -> t (WL.WriterT w m) b | ||
340 | writerC p = do | ||
341 | (r, w) <- hoist lift p | ||
342 | lift $ WL.tell w | ||
343 | return r | ||
344 | {-# INLINABLE writerC #-} | ||
345 | |||
346 | -- | Run 'WL.WriterT' in the base monad | ||
347 | -- | ||
348 | -- Since 1.0.11 | ||
349 | runWriterC | ||
350 | :: (Monad m, Monoid w) => | ||
351 | ConduitM i o (WL.WriterT w m) r -> ConduitM i o m (r, w) | ||
352 | runWriterC = thread (,) run mempty | ||
353 | where | ||
354 | run m w = do | ||
355 | (a, w') <- WL.runWriterT m | ||
356 | return (a, w `mappend` w') | ||
357 | {-# INLINABLE runWriterC #-} | ||
358 | |||
359 | -- | Execute 'WL.WriterT' in the base monad | ||
360 | -- | ||
361 | -- Since 1.0.11 | ||
362 | execWriterC | ||
363 | :: (Monad m, Monoid w) => | ||
364 | ConduitM i o (WL.WriterT w m) r -> ConduitM i o m w | ||
365 | execWriterC p = fmap snd $ runWriterC p | ||
366 | {-# INLINABLE execWriterC #-} | ||
367 | |||
368 | |||
369 | -- | Wrap the base monad in 'WS.WriterT' | ||
370 | -- | ||
371 | -- Since 1.0.11 | ||
372 | writerSC | ||
373 | :: (Monad m, Monad (t (WS.WriterT w m)), MonadTrans t, Monoid w, | ||
374 | MFunctor t) => | ||
375 | t m (b, w) -> t (WS.WriterT w m) b | ||
376 | writerSC p = do | ||
377 | (r, w) <- hoist lift p | ||
378 | lift $ WS.tell w | ||
379 | return r | ||
380 | {-# INLINABLE writerSC #-} | ||
381 | |||
382 | -- | Run 'WS.WriterT' in the base monad | ||
383 | -- | ||
384 | -- Since 1.0.11 | ||
385 | runWriterSC | ||
386 | :: (Monad m, Monoid w) => | ||
387 | ConduitM i o (WS.WriterT w m) r -> ConduitM i o m (r, w) | ||
388 | runWriterSC = thread (,) run mempty | ||
389 | where | ||
390 | run m w = do | ||
391 | (a, w') <- WS.runWriterT m | ||
392 | return (a, w `mappend` w') | ||
393 | {-# INLINABLE runWriterSC #-} | ||
394 | |||
395 | -- | Execute 'WS.WriterT' in the base monad | ||
396 | -- | ||
397 | -- Since 1.0.11 | ||
398 | execWriterSC | ||
399 | :: (Monad m, Monoid w) => | ||
400 | ConduitM i o (WS.WriterT w m) r -> ConduitM i o m w | ||
401 | execWriterSC p = fmap snd $ runWriterSC p | ||
402 | {-# INLINABLE execWriterSC #-} | ||
403 | |||
404 | |||
405 | -- | Wrap the base monad in 'RWSL.RWST' | ||
406 | -- | ||
407 | -- Since 1.0.11 | ||
408 | rwsC | ||
409 | :: (Monad m, Monad (t1 (RWSL.RWST t w t2 m)), MonadTrans t1, | ||
410 | Monoid w, MFunctor t1) => | ||
411 | (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWSL.RWST t w t2 m) b | ||
412 | rwsC k = do | ||
413 | i <- lift RWSL.ask | ||
414 | s <- lift RWSL.get | ||
415 | (r, s', w) <- hoist lift (k i s) | ||
416 | lift $ do | ||
417 | RWSL.put s' | ||
418 | RWSL.tell w | ||
419 | return r | ||
420 | {-# INLINABLE rwsC #-} | ||
421 | |||
422 | -- | Run 'RWSL.RWST' in the base monad | ||
423 | -- | ||
424 | -- Since 1.0.11 | ||
425 | runRWSC | ||
426 | :: (Monad m, Monoid w) => | ||
427 | r | ||
428 | -> s | ||
429 | -> ConduitM i o (RWSL.RWST r w s m) res | ||
430 | -> ConduitM i o m (res, s, w) | ||
431 | runRWSC r s0 = thread toRes run (s0, mempty) | ||
432 | where | ||
433 | toRes a (s, w) = (a, s, w) | ||
434 | run m (s, w) = do | ||
435 | (res, s', w') <- RWSL.runRWST m r s | ||
436 | return (res, (s', w `mappend` w')) | ||
437 | {-# INLINABLE runRWSC #-} | ||
438 | |||
439 | -- | Evaluate 'RWSL.RWST' in the base monad | ||
440 | -- | ||
441 | -- Since 1.0.11 | ||
442 | evalRWSC | ||
443 | :: (Monad m, Monoid w) => | ||
444 | r | ||
445 | -> s | ||
446 | -> ConduitM i o (RWSL.RWST r w s m) res | ||
447 | -> ConduitM i o m (res, w) | ||
448 | evalRWSC i s p = fmap f $ runRWSC i s p | ||
449 | where f x = let (r, _, w) = x in (r, w) | ||
450 | {-# INLINABLE evalRWSC #-} | ||
451 | |||
452 | -- | Execute 'RWSL.RWST' in the base monad | ||
453 | -- | ||
454 | -- Since 1.0.11 | ||
455 | execRWSC | ||
456 | :: (Monad m, Monoid w) => | ||
457 | r | ||
458 | -> s | ||
459 | -> ConduitM i o (RWSL.RWST r w s m) res | ||
460 | -> ConduitM i o m (s, w) | ||
461 | execRWSC i s p = fmap f $ runRWSC i s p | ||
462 | where f x = let (_, s2, w2) = x in (s2, w2) | ||
463 | {-# INLINABLE execRWSC #-} | ||
464 | |||
465 | |||
466 | -- | Wrap the base monad in 'RWSS.RWST' | ||
467 | -- | ||
468 | -- Since 1.0.11 | ||
469 | rwsSC | ||
470 | :: (Monad m, Monad (t1 (RWSS.RWST t w t2 m)), MonadTrans t1, | ||
471 | Monoid w, MFunctor t1) => | ||
472 | (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWSS.RWST t w t2 m) b | ||
473 | rwsSC k = do | ||
474 | i <- lift RWSS.ask | ||
475 | s <- lift RWSS.get | ||
476 | (r, s', w) <- hoist lift (k i s) | ||
477 | lift $ do | ||
478 | RWSS.put s' | ||
479 | RWSS.tell w | ||
480 | return r | ||
481 | {-# INLINABLE rwsSC #-} | ||
482 | |||
483 | -- | Run 'RWSS.RWST' in the base monad | ||
484 | -- | ||
485 | -- Since 1.0.11 | ||
486 | runRWSSC | ||
487 | :: (Monad m, Monoid w) => | ||
488 | r | ||
489 | -> s | ||
490 | -> ConduitM i o (RWSS.RWST r w s m) res | ||
491 | -> ConduitM i o m (res, s, w) | ||
492 | runRWSSC r s0 = thread toRes run (s0, mempty) | ||
493 | where | ||
494 | toRes a (s, w) = (a, s, w) | ||
495 | run m (s, w) = do | ||
496 | (res, s', w') <- RWSS.runRWST m r s | ||
497 | return (res, (s', w `mappend` w')) | ||
498 | {-# INLINABLE runRWSSC #-} | ||
499 | |||
500 | -- | Evaluate 'RWSS.RWST' in the base monad | ||
501 | -- | ||
502 | -- Since 1.0.11 | ||
503 | evalRWSSC | ||
504 | :: (Monad m, Monoid w) => | ||
505 | r | ||
506 | -> s | ||
507 | -> ConduitM i o (RWSS.RWST r w s m) res | ||
508 | -> ConduitM i o m (res, w) | ||
509 | evalRWSSC i s p = fmap f $ runRWSSC i s p | ||
510 | where f x = let (r, _, w) = x in (r, w) | ||
511 | {-# INLINABLE evalRWSSC #-} | ||
512 | |||
513 | -- | Execute 'RWSS.RWST' in the base monad | ||
514 | -- | ||
515 | -- Since 1.0.11 | ||
516 | execRWSSC | ||
517 | :: (Monad m, Monoid w) => | ||
518 | r | ||
519 | -> s | ||
520 | -> ConduitM i o (RWSS.RWST r w s m) res | ||
521 | -> ConduitM i o m (s, w) | ||
522 | execRWSSC i s p = fmap f $ runRWSSC i s p | ||
523 | where f x = let (_, s2, w2) = x in (s2, w2) | ||
524 | {-# INLINABLE execRWSSC #-} | ||
525 | |||
526 | |||