1 {-# LANGUAGE CPP #-}

3 {-# LANGUAGE Safe #-}

4 #endif

6 {-# LANGUAGE AutoDeriveTypeable #-}

7 #endif

8 -----------------------------------------------------------------------------

9 -- |

10 -- Module : Control.Monad.Trans.Class

11 -- Copyright : (c) Andy Gill 2001,

12 -- (c) Oregon Graduate Institute of Science and Technology, 2001

13 -- License : BSD-style (see the file LICENSE)

14 --

15 -- Maintainer : R.Paterson@city.ac.uk

16 -- Stability : experimental

17 -- Portability : portable

18 --

19 -- The class of monad transformers.

20 --

21 -- A monad transformer makes a new monad out of an existing monad, such

22 -- that computations of the old monad may be embedded in the new one.

23 -- To construct a monad with a desired set of features, one typically

24 -- starts with a base monad, such as 'Data.Functor.Identity.Identity', @[]@ or 'IO', and

25 -- applies a sequence of monad transformers.

26 -----------------------------------------------------------------------------

29 -- * Transformer class

30 MonadTrans(..)

32 -- * Conventions

33 -- $conventions

35 -- * Strict monads

36 -- $strict

38 -- * Examples

39 -- ** Parsing

40 -- $example1

42 -- ** Parsing and counting

43 -- $example2

45 -- ** Interpreter monad

46 -- $example3

49 -- | The class of monad transformers. Instances should satisfy the

50 -- following laws, which state that 'lift' is a monad transformation:

51 --

52 -- * @'lift' . 'return' = 'return'@

53 --

54 -- * @'lift' (m >>= f) = 'lift' m >>= ('lift' . f)@

57 -- | Lift a computation from the argument monad to the constructed monad.

60 {- $conventions

61 Most monad transformer modules include the special case of applying

62 the transformer to 'Data.Functor.Identity.Identity'. For example,

63 @'Control.Monad.Trans.State.Lazy.State' s@ is an abbreviation for

64 @'Control.Monad.Trans.State.Lazy.StateT' s 'Data.Functor.Identity.Identity'@.

66 Each monad transformer also comes with an operation @run@/XXX/@T@ to

67 unwrap the transformer, exposing a computation of the inner monad.

68 (Currently these functions are defined as field labels, but in the next

69 major release they will be separate functions.)

71 All of the monad transformers except 'Control.Monad.Trans.Cont.ContT'

72 and 'Control.Monad.Trans.Cont.SelectT' are functors on the category

73 of monads: in addition to defining a mapping of monads, they

74 also define a mapping from transformations between base monads to

75 transformations between transformed monads, called @map@/XXX/@T@.

76 Thus given a monad transformation @t :: M a -> N a@, the combinator

77 'Control.Monad.Trans.State.Lazy.mapStateT' constructs a monad

78 transformation

80 > mapStateT t :: StateT s M a -> StateT s N a

82 For these monad transformers, 'lift' is a natural transformation in the

83 category of monads, i.e. for any monad transformation @t :: M a -> N a@,

85 * @map@/XXX/@T t . 'lift' = 'lift' . t@

87 Each of the monad transformers introduces relevant operations.

88 In a sequence of monad transformers, most of these operations.can be

89 lifted through other transformers using 'lift' or the @map@/XXX/@T@

90 combinator, but a few with more complex type signatures require

91 specialized lifting combinators, called @lift@/Op/

92 (see "Control.Monad.Signatures").

93 -}

95 {- $strict

97 A monad is said to be /strict/ if its '>>=' operation is strict in its first

98 argument. The base monads 'Maybe', @[]@ and 'IO' are strict:

100 >>> undefined >> return 2 :: Maybe Integer

101 *** Exception: Prelude.undefined

103 However the monad 'Data.Functor.Identity.Identity' is not:

105 >>> runIdentity (undefined >> return 2)

106 2

108 In a strict monad you know when each action is executed, but the monad

109 is not necessarily strict in the return value, or in other components

110 of the monad, such as a state. However you can use 'seq' to create

111 an action that is strict in the component you want evaluated.

112 -}

114 {- $example1

116 One might define a parsing monad by adding a state (the 'String' remaining

117 to be parsed) to the @[]@ monad, which provides non-determinism:

119 > import Control.Monad.Trans.State

120 >

121 > type Parser = StateT String []

123 Then @Parser@ is an instance of @MonadPlus@: monadic sequencing implements

124 concatenation of parsers, while @mplus@ provides choice. To use parsers,

125 we need a primitive to run a constructed parser on an input string:

127 > runParser :: Parser a -> String -> [a]

128 > runParser p s = [x | (x, "") <- runStateT p s]

130 Finally, we need a primitive parser that matches a single character,

131 from which arbitrarily complex parsers may be constructed:

133 > item :: Parser Char

134 > item = do

135 > c:cs <- get

136 > put cs

137 > return c

139 In this example we use the operations @get@ and @put@ from

140 "Control.Monad.Trans.State", which are defined only for monads that are

141 applications of 'Control.Monad.Trans.State.Lazy.StateT'. Alternatively one

142 could use monad classes from the @mtl@ package or similar, which contain

143 methods @get@ and @put@ with types generalized over all suitable monads.

144 -}

146 {- $example2

148 We can define a parser that also counts by adding a

149 'Control.Monad.Trans.Writer.Lazy.WriterT' transformer:

151 > import Control.Monad.Trans.Class

152 > import Control.Monad.Trans.State

153 > import Control.Monad.Trans.Writer

154 > import Data.Monoid

155 >

156 > type Parser = WriterT (Sum Int) (StateT String [])

158 The function that applies a parser must now unwrap each of the monad

159 transformers in turn:

161 > runParser :: Parser a -> String -> [(a, Int)]

162 > runParser p s = [(x, n) | ((x, Sum n), "") <- runStateT (runWriterT p) s]

164 To define the @item@ parser, we need to lift the

165 'Control.Monad.Trans.State.Lazy.StateT' operations through the

166 'Control.Monad.Trans.Writer.Lazy.WriterT' transformer.

168 > item :: Parser Char

169 > item = do

170 > c:cs <- lift get

171 > lift (put cs)

172 > return c

174 In this case, we were able to do this with 'lift', but operations with

175 more complex types require special lifting functions, which are provided

176 by monad transformers for which they can be implemented. If you use the

177 monad classes of the @mtl@ package or similar, this lifting is handled

178 automatically by the instances of the classes, and you need only use

179 the generalized methods @get@ and @put@.

181 We can also define a primitive using the Writer:

183 > tick :: Parser ()

184 > tick = tell (Sum 1)

186 Then the parser will keep track of how many @tick@s it executes.

187 -}

189 {- $example3

191 This example is a cut-down version of the one in

192 \"Monad Transformers and Modular Interpreters\",

193 by Sheng Liang, Paul Hudak and Mark Jones in /POPL'95/

194 (<http://web.cecs.pdx.edu/~mpj/pubs/modinterp.html>).

196 Suppose we want to define an interpreter that can do I\/O and has

197 exceptions, an environment and a modifiable store. We can define

198 a monad that supports all these things as a stack of monad transformers:

200 > import Control.Monad.Trans.Class

201 > import Control.Monad.Trans.State

202 > import qualified Control.Monad.Trans.Reader as R

203 > import qualified Control.Monad.Trans.Except as E

204 > import Control.Monad.IO.Class

205 >

206 > type InterpM = StateT Store (R.ReaderT Env (E.ExceptT Err IO))

208 for suitable types @Store@, @Env@ and @Err@.

210 Now we would like to be able to use the operations associated with each

211 of those monad transformers on @InterpM@ actions. Since the uppermost

212 monad transformer of @InterpM@ is 'Control.Monad.Trans.State.Lazy.StateT',

213 it already has the state operations @get@ and @set@.

215 The first of the 'Control.Monad.Trans.Reader.ReaderT' operations,

216 'Control.Monad.Trans.Reader.ask', is a simple action, so we can lift it

217 through 'Control.Monad.Trans.State.Lazy.StateT' to @InterpM@ using 'lift':

219 > ask :: InterpM Env

220 > ask = lift R.ask

222 The other 'Control.Monad.Trans.Reader.ReaderT' operation,

223 'Control.Monad.Trans.Reader.local', has a suitable type for lifting

224 using 'Control.Monad.Trans.State.Lazy.mapStateT':

226 > local :: (Env -> Env) -> InterpM a -> InterpM a

227 > local f = mapStateT (R.local f)

229 We also wish to lift the operations of 'Control.Monad.Trans.Except.ExceptT'

230 through both 'Control.Monad.Trans.Reader.ReaderT' and

231 'Control.Monad.Trans.State.Lazy.StateT'. For the operation

232 'Control.Monad.Trans.Except.throwE', we know @throwE e@ is a simple

233 action, so we can lift it through the two monad transformers to @InterpM@

234 with two 'lift's:

236 > throwE :: Err -> InterpM a

237 > throwE e = lift (lift (E.throwE e))

239 The 'Control.Monad.Trans.Except.catchE' operation has a more

240 complex type, so we need to use the special-purpose lifting function

241 @liftCatch@ provided by most monad transformers. Here we use

242 the 'Control.Monad.Trans.Reader.ReaderT' version followed by the

243 'Control.Monad.Trans.State.Lazy.StateT' version:

245 > catchE :: InterpM a -> (Err -> InterpM a) -> InterpM a

246 > catchE = liftCatch (R.liftCatch E.catchE)

248 We could lift 'IO' actions to @InterpM@ using three 'lift's, but @InterpM@

249 is automatically an instance of 'Control.Monad.IO.Class.MonadIO',

250 so we can use 'Control.Monad.IO.Class.liftIO' instead:

252 > putStr :: String -> InterpM ()

253 > putStr s = liftIO (Prelude.putStr s)

255 -}