diff options
Diffstat (limited to 'TraversableT.hs')
-rw-r--r-- | TraversableT.hs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/TraversableT.hs b/TraversableT.hs new file mode 100644 index 00000000..c0e40853 --- /dev/null +++ b/TraversableT.hs | |||
@@ -0,0 +1,94 @@ | |||
1 | module TraversableT where | ||
2 | |||
3 | import Data.Traversable | ||
4 | import Control.Monad (join,MonadPlus(..)) | ||
5 | import Control.Monad.Trans.Class (MonadTrans(..)) | ||
6 | import Control.Applicative | ||
7 | import Data.Foldable (Foldable(foldMap), toList) | ||
8 | import Data.Maybe (maybeToList) | ||
9 | |||
10 | -- | | ||
11 | -- | ||
12 | -- /Note:/ this does not yield a monad unless the argument monad is commutative. | ||
13 | newtype TraversableT t m a = TraversableT { runTraversableT :: m (t a) } | ||
14 | |||
15 | -- | Map between 'TraversableT' computations. | ||
16 | -- | ||
17 | -- * @'runTraversableT' ('mapTraversableT' f m) = f ('runTraversableT' m)@ | ||
18 | mapTraversableT :: (m (t a) -> n (t b)) -> TraversableT t m a -> TraversableT t n b | ||
19 | mapTraversableT f m = TraversableT $ f (runTraversableT m) | ||
20 | |||
21 | |||
22 | instance (Functor m, Functor t) => Functor (TraversableT t m) where | ||
23 | fmap f = mapTraversableT $ fmap $ fmap f | ||
24 | |||
25 | instance (Foldable f, Foldable t) => Foldable (TraversableT t f) where | ||
26 | foldMap f (TraversableT a) = foldMap (foldMap f) a | ||
27 | |||
28 | instance (Traversable f, Traversable t) => Traversable (TraversableT t f) where | ||
29 | traverse f (TraversableT a) = TraversableT <$> traverse (traverse f) a | ||
30 | |||
31 | instance (Applicative m,Applicative t) => Applicative (TraversableT t m) where | ||
32 | pure a = TraversableT $ pure (pure a) | ||
33 | f <*> v = TraversableT $ (<*>) <$> runTraversableT f <*> runTraversableT v | ||
34 | |||
35 | instance (Applicative m, Alternative t) => Alternative (TraversableT t m) where | ||
36 | empty = TraversableT $ pure empty | ||
37 | m <|> n = TraversableT $ (<|>) <$> runTraversableT m <*> runTraversableT n | ||
38 | |||
39 | instance (Monad m, Traversable t, Monad t) => Monad (TraversableT t m) where | ||
40 | return = TraversableT . return . return | ||
41 | m >>= k = TraversableT $ do | ||
42 | a <- runTraversableT m | ||
43 | b <- forM a $ runTraversableT . k | ||
44 | return (join b) | ||
45 | fail s = TraversableT $ return (fail s) | ||
46 | |||
47 | instance (Monad m, Traversable t, MonadPlus t) => MonadPlus (TraversableT t m) where | ||
48 | mzero = TraversableT $ return mzero | ||
49 | m `mplus` n = TraversableT $ do | ||
50 | a <- runTraversableT m | ||
51 | b <- runTraversableT n | ||
52 | return (a `mplus` b) | ||
53 | |||
54 | instance Applicative t => MonadTrans (TraversableT t) where | ||
55 | lift m = TraversableT $ do | ||
56 | a <- m | ||
57 | return (pure a) | ||
58 | |||
59 | liftT :: Monad m => t a -> TraversableT t m a | ||
60 | liftT = TraversableT . return | ||
61 | |||
62 | liftMT :: m (t a) -> TraversableT t m a | ||
63 | liftMT = TraversableT | ||
64 | |||
65 | -- | Lift a @callCC@ operation to the new monad. | ||
66 | liftCallCC :: Applicative t => | ||
67 | ((( (t a) -> m (t b)) -> m (t a)) -> m (t a)) -> | ||
68 | ((a -> TraversableT t m b) -> TraversableT t m a) -> TraversableT t m a | ||
69 | liftCallCC callCC f = TraversableT $ | ||
70 | callCC $ \c -> | ||
71 | runTraversableT (f (\a -> TraversableT $ c (pure a))) | ||
72 | |||
73 | -- | Lift a @catchError@ operation to the new monad. | ||
74 | liftCatch :: (m (t a) -> (e -> m (t a)) -> m (t a)) -> | ||
75 | TraversableT t m a -> (e -> TraversableT t m a) -> TraversableT t m a | ||
76 | liftCatch catchError m h = TraversableT $ runTraversableT m | ||
77 | `catchError` \e -> runTraversableT (h e) | ||
78 | |||
79 | liftMaybe :: Monad m => Maybe a -> TraversableT [] m a | ||
80 | liftMaybe = liftT . maybeToList | ||
81 | |||
82 | liftIOMaybe :: IO (Maybe a) -> TraversableT [] IO a | ||
83 | liftIOMaybe = liftMT . fmap maybeToList | ||
84 | |||
85 | handleT :: ( Monad m | ||
86 | , Traversable t ) => | ||
87 | (t a -> TraversableT t m a) | ||
88 | -> TraversableT t m a | ||
89 | -> TraversableT t m a | ||
90 | handleT catcher body = TraversableT $ do | ||
91 | tx <- runTraversableT body | ||
92 | if null (toList tx) | ||
93 | then runTraversableT $ catcher tx | ||
94 | else return tx | ||