on master help sign in
WriterT transformer
commitee5e65c52651db78c6ab174dbd46b42e77e3dc20 authorIndex Int <vlad.z.4096@gmail.com> dateSat 13 Jun 2015, 01:05 (11 years ago) parent3012b99
5 files changed+177−9
ether.cabal+1 src/Control/Ether/Util.hs+15 src/Control/Monad/Trans/Ether/Except.hs+2−2 src/Control/Monad/Trans/Ether/State.hs+5−7 src/Control/Monad/Trans/Ether/Writer.hs+154
ether.cabal+1
@@ -27,6 +27,7 @@ library
2727 Control.Ether.TH
2828 Control.Ether.Wrapped
2929 Control.Monad.Trans.Ether.Reader
30+ Control.Monad.Trans.Ether.Writer
3031 Control.Monad.Trans.Ether.State
3132 Control.Monad.Trans.Ether.Except
3233 Control.Monad.Ether.Reader
src/Control/Ether/Util.hs+15
@@ -3,12 +3,15 @@
33{-# LANGUAGE TypeFamilies #-}
44module Control.Ether.Util
55 ( liftCatch_ExceptT
6+ , liftListen_WriterT
7+ , liftPass_WriterT
68 , type (++)
79 , MaybeToList
810 ) where
911
1012import qualified Control.Monad.Signatures as Sig
1113import qualified Control.Monad.Trans.Except as Trans
14+import qualified Control.Monad.Trans.Writer as Trans
1215
1316type family (as :: [*]) ++ (bs :: [*]) :: [*] where
1417 '[] ++ bs = bs
@@ -20,3 +23,15 @@ type family MaybeToList (mt :: Maybe k) :: [k] where
2023
2124liftCatch_ExceptT :: Sig.Catch e m (Either e' a) -> Sig.Catch e (Trans.ExceptT e' m) a
2225liftCatch_ExceptT catchE m h = Trans.ExceptT $ catchE (Trans.runExceptT m) (Trans.runExceptT . h)
26+
27+-- TODO: Not sure if correct
28+liftListen_WriterT :: Monad m => Sig.Listen w' m (a, w) -> Sig.Listen w' (Trans.WriterT w m) a
29+liftListen_WriterT listen m = Trans.WriterT $ do
30+ ~((a, w'), w) <- listen (Trans.runWriterT m)
31+ return ((a, w), w')
32+
33+-- TODO: Not sure if correct
34+liftPass_WriterT :: Monad m => Sig.Pass w' m (a, w) -> Sig.Pass w' (Trans.WriterT w m) a
35+liftPass_WriterT pass m = Trans.WriterT $ pass $ do
36+ ~((a, f), w) <- Trans.runWriterT m
37+ return ((a, w), f)
src/Control/Monad/Trans/Ether/Except.hs+2−2
@@ -88,8 +88,8 @@ exceptT t = tagged t . Trans.ExceptT
8888
8989-- | Constructor for computations in the exception monad
9090-- (the inverse of 'runExcept').
91−except :: proxy tag -> Either e a -> Except tag e a
92−except t = tagged t . Trans.except
91+except :: Monad m => proxy tag -> Either e a -> ExceptT tag e m a
92+except t = exceptT t . return
9393
9494-- | Runs an 'ExceptT' and returns either an exception or a normal value.
9595runExceptT :: proxy tag -> ExceptT tag e m a -> m (Either e a)
src/Control/Monad/Trans/Ether/State.hs+5−7
@@ -59,15 +59,13 @@ import qualified Control.Monad.Error.Class as Class
5959-- Computations have access to a mutable state.
6060--
6161-- The 'return' function leaves the state unchanged, while '>>=' uses
62−-- the final state of the first computation as the initial state of
63−-- the second.
62+-- the final state of the first computation as the initial state of the second.
6463type State tag r = StateT tag r Identity
6564
6665-- | The state monad transformer.
6766--
6867-- The 'return' function leaves the state unchanged, while '>>=' uses
69−-- the final state of the first computation as the initial state of
70−-- the second.
68+-- the final state of the first computation as the initial state of the second.
7169newtype StateT tag s m a = StateT (Trans.StateT s m a)
7270 deriving ( Generic
7371 , Functor, Applicative, Alternative, Monad, MonadPlus
@@ -93,17 +91,17 @@ state t = tagged t . Trans.state
9391
9492-- | Runs a 'StateT' with the given initial state
9593-- and returns both the final value and the final state.
96−runStateT :: proxy tag -> StateT tag s m a -> s -> m (a, s)
94+runStateT :: proxy tag -> StateT tag s m a -> s -> m (a, s)
9795runStateT t = Trans.runStateT . untagged t
9896
9997-- | Runs a 'StateT' with the given initial state
10098-- and returns the final value, discarding the final state.
101−evalStateT :: Monad m => proxy tag -> StateT tag s m a -> s -> m a
99+evalStateT :: Monad m => proxy tag -> StateT tag s m a -> s -> m a
102100evalStateT t = Trans.evalStateT . untagged t
103101
104102-- | Runs a 'StateT' with the given initial state
105103-- and returns the final state, discarding the final value.
106−execStateT :: Monad m => proxy tag -> StateT tag s m a -> s -> m s
104+execStateT :: Monad m => proxy tag -> StateT tag s m a -> s -> m s
107105execStateT t = Trans.execStateT . untagged t
108106
109107-- | Runs a 'State' with the given initial state
src/Control/Monad/Trans/Ether/Writer.hsnew file+154
@@ -0,0 +1,154 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE MultiParamTypeClasses #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE FlexibleContexts #-}
6+{-# LANGUAGE UndecidableInstances #-}
7+{-# LANGUAGE DataKinds #-}
8+{-# LANGUAGE TypeOperators #-}
9+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10+module Control.Monad.Trans.Ether.Writer
11+ (
12+ -- * The Writer monad
13+ Writer
14+ , writer
15+ , runWriter
16+ , execWriter
17+ -- * The WriterT monad transformer
18+ , WriterT
19+ , writerT
20+ , runWriterT
21+ , execWriterT
22+ , mapWriterT
23+ -- * Writer operations
24+ , tell
25+ -- * Lifting other operations
26+ , liftCallCC
27+ , liftCatch
28+ ) where
29+
30+import Data.Proxy (Proxy(Proxy))
31+import Data.Functor.Identity (Identity(..))
32+import Data.Coerce (coerce)
33+import Control.Applicative (Alternative)
34+import Control.Monad (MonadPlus)
35+import Control.Monad.Fix (MonadFix)
36+import Control.Monad.Trans.Class (MonadTrans, lift)
37+import Control.Monad.IO.Class (MonadIO)
38+import Control.Ether.Tags (Taggable(..), Tagged(..))
39+import qualified Control.Ether.Util as Util
40+import GHC.Generics (Generic)
41+import qualified Control.Newtype as NT
42+
43+import qualified Control.Monad.Signatures as Sig
44+import qualified Control.Monad.Trans.Writer.Lazy as Trans
45+
46+import qualified Control.Monad.Cont.Class as Class
47+import qualified Control.Monad.Reader.Class as Class
48+import qualified Control.Monad.State.Class as Class
49+import qualified Control.Monad.Writer.Class as Class
50+import qualified Control.Monad.Error.Class as Class
51+
52+-- | The parametrizable writer monad.
53+--
54+-- Computations can accumulate a monoid value.
55+--
56+-- The 'return' function produces the output 'mempty', while '>>=' combines
57+-- the outputs of the subcomputations using 'mappend'.
58+type Writer tag w = WriterT tag w Identity
59+
60+-- | The writer monad transformer.
61+--
62+-- The 'return' function produces the output 'mempty', while '>>=' combines
63+-- the outputs of the subcomputations using 'mappend'.
64+newtype WriterT tag w m a = WriterT (Trans.WriterT w m a)
65+ deriving ( Generic
66+ , Functor, Applicative, Alternative, Monad, MonadPlus
67+ , MonadFix, MonadTrans, MonadIO )
68+
69+instance NT.Newtype (WriterT tag w m a)
70+
71+instance Taggable (WriterT tag w m) where
72+ type Tag (WriterT tag w m) = 'Just tag
73+ type Inner (WriterT tag w m) = 'Just m
74+
75+instance Tagged (WriterT tag w m) tag where
76+ type Untagged (WriterT tag w m) = Trans.WriterT w m
77+
78+-- | Constructor for computations in the writer monad transformer.
79+writerT :: proxy tag -> m (a, w) -> WriterT tag w m a
80+writerT t = tagged t . Trans.WriterT
81+
82+-- | Constructor for computations in the writer monad
83+-- (the inverse of 'runWriter').
84+writer :: Monad m => proxy tag -> (a, w) -> WriterT tag w m a
85+writer t = tagged t . Trans.writer
86+
87+-- | Runs a 'WriterT' and returns both the normal value
88+-- and the final accumulator.
89+runWriterT :: proxy tag -> WriterT tag w m a -> m (a, w)
90+runWriterT t = Trans.runWriterT . untagged t
91+
92+-- | Runs a 'Writer' and returns both the normal value
93+-- and the final accumulator.
94+runWriter :: proxy tag -> Writer tag w a -> (a, w)
95+runWriter t = Trans.runWriter . untagged t
96+
97+-- | Runs a 'WriterT' and returns the final accumulator,
98+-- discarding the normal value.
99+execWriterT :: Monad m => proxy tag -> WriterT tag w m a -> m w
100+execWriterT t = Trans.execWriterT . untagged t
101+
102+-- | Runs a 'Writer' and returns the final accumulator,
103+-- discarding the normal value.
104+execWriter :: proxy tag -> Writer tag w a -> w
105+execWriter t = Trans.execWriter . untagged t
106+
107+-- | Transform the computation inside a 'WriterT'.
108+--
109+-- * @'runWriterT' tag ('mapWriterT' tag f m) = f ('runWriterT' tag m)@
110+mapWriterT :: proxy tag -> (m (a, w) -> n (b, w')) -> WriterT tag w m a -> WriterT tag w' n b
111+mapWriterT t f m = tagged t $ Trans.mapWriterT f (coerce m)
112+
113+-- | Appends a value to the accumulator within the monad.
114+tell :: Monad m => proxy tag -> w -> WriterT tag w m ()
115+tell t w = writer t ((), w)
116+
117+-- | Lift a @catchE@ operation to the new monad.
118+liftCatch :: proxy tag -> Sig.Catch e m (a, w) -> Sig.Catch e (WriterT tag w m) a
119+liftCatch t f m h = tagged t $ Trans.liftCatch f (coerce m) (coerce h)
120+
121+-- | Lift a @callCC@ operation to the new monad.
122+liftCallCC :: Monoid w => proxy tag -> Sig.CallCC m (a, w) (b, w) -> Sig.CallCC (WriterT tag w m) a b
123+liftCallCC t callCC f = tagged t $ Trans.liftCallCC callCC (coerce f)
124+
125+-- | Lift a @listen@ operation to the new monad.
126+liftListen :: Monad m => proxy tag -> Sig.Listen w' m (a, w) -> Sig.Listen w' (WriterT tag w m) a
127+liftListen t listen m = tagged t $ Util.liftListen_WriterT listen (coerce m)
128+
129+-- | Lift a @pass@ operation to the new monad.
130+liftPass :: Monad m => proxy tag -> Sig.Pass w' m (a, w) -> Sig.Pass w' (WriterT tag w m) a
131+liftPass t pass m = tagged t $ Util.liftPass_WriterT pass (coerce m)
132+
133+instance (Monoid w, Class.MonadCont m) => Class.MonadCont (WriterT tag w m) where
134+ callCC = liftCallCC Proxy Class.callCC
135+
136+instance (Monoid w, Class.MonadReader r m) => Class.MonadReader r (WriterT tag w m) where
137+ ask = lift Class.ask
138+ local = mapWriterT Proxy . Class.local
139+ reader = lift . Class.reader
140+
141+instance (Monoid w, Class.MonadState s m) => Class.MonadState s (WriterT tag w m) where
142+ get = lift Class.get
143+ put = lift . Class.put
144+ state = lift . Class.state
145+
146+instance (Monoid w, Class.MonadWriter w' m) => Class.MonadWriter w' (WriterT tag w m) where
147+ writer = lift . Class.writer
148+ tell = lift . Class.tell
149+ listen = liftListen Proxy Class.listen
150+ pass = liftPass Proxy Class.pass
151+
152+instance (Monoid w, Class.MonadError e m) => Class.MonadError e (WriterT tag w m) where
153+ throwError = lift . Class.throwError
154+ catchError = liftCatch Proxy Class.catchError