11.0.2.3
2
3* Correct spelling mistake. Courtesy of Edward Betts.
4
5* Support transformers-compat-0.6.
6
7
81.0.2.2
9
10* Added some good documentation. Courtesy of Franz Thoma.
11
12
131.0.2.1
14
15* Refer to Michael Snoyman's excellent tutorial on monad-control.
16
17
181.0.2.0
19
20* Improve documentation by including type equalities in the Haddock documentation.
21
22* Add helpers to define MonadTransControl for stack of two:
23  RunDefault2, defaultLiftWith2, defaultRestoreT2
24
251.0.1.0
26
27* Added the functions:
28
29  liftThrough
30    :: (MonadTransControl t, Monad (t m), Monad m)
31    => (m (StT t a) -> m (StT t b)) -- ^
32    -> t m a -> t m b
33
34  captureT :: (MonadTransControl t, Monad (t m), Monad m) => t m (StT t ())
35  captureM :: MonadBaseControl b m => m (StM m ())
36
37* Added Travis-CI integration
38
39
401.0.0.5
41
42* Support transformers-0.5 & ransformers-compat-0.5.*.
43
44
451.0.0.4
46
47* Support transformers-compat-0.4.*.
48
49
501.0.0.3
51
52* Unconditionally add ExceptT instances using transformers-compat.
53  Courtesy of Adam Bergmark.
54
55
561.0.0.2
57
58* Add a base >= 4.5 constraint because monad-control only builds on GHC >= 7.4.
59
60
611.0.0.1
62
63* Use Safe instead of Trustworthy.
64
65  This requires a dependency on stm.
66
67
681.0.0.0
69
70* Switch the associated data types StT and StM to associated type synonyms.
71
72  This is an API breaking change. To fix your MonadTransControl or
73  MonadBaseControl instances simply remove the StT or StM constructors
74  and deconstructors for your monad transformers or monad.
75
76* Add the embed, embed_ and liftBaseOpDiscard functions.
77
78
790.3.3.1
80
81* Unconditionally add ExceptT instances using transformers-compat.
82  Courtesy of Adam Bergmark.
83
84
850.3.3.0
86
87* Support transformers-0.4.0.0
88
89* Drop unicode syntax and symbols
90
91
920.3.2.3
93
94*  Fix haddock documentation error
95
96
970.3.2.2
98
99*  Fix preprocessor directive for GHC 7.6.3
100
101
1020.3.2.1
103
104* Resolve #14. Bump upper version bound of base to 5
105
106
1070.3.2
108
109* Added defaultLiftWith and defaultRestoreT to simplify defining
110  MonadTransControl for newtypes.
111
112
1130.3.1.4
114
115* Compatibility with ghc head
116
117
1180.3.1.3
119
120* Added a Trustworthy flag
121
122
1230.3.1.2
124
125* Fix issue #9. Replace all Unicode in type variables.
126
127
1280.3.1.1
129
130* Add MonadBaseControl instances for ST and STM.
131
132
1330.3
134
135(Released on: Fri Dec 2 09:52:16 UTC 2011)
136
137* Major new API which IMHO is easier to understand than the old one.
138
139* On average about 60 times faster than the previous release!
140
141* New package lifted-base providing lifted versions of functions from the base
142  library. It exports the following modules:
143
144  - Control.Exception.Lifted
145  - Control.Concurrent.Lifted
146  - Control.Concurrent.MVar.Lifted
147  - System.Timeout.Lifted
148
149  Not all modules from base are converted yet. If you need a lifted version of
150  some function from base, just ask me to add it or send me a patch.
151
152
1530.2.0.3
154
155(Released on: Sat Aug 27 21:18:22 UTC 2011)
156
157* Fixed issue #2
158  https://github.com/basvandijk/monad-control/issues/2
159
160
1610.2.0.2
162
163(Released on: Mon Aug 8 09:16:08 UTC 2011)
164
165* Switched to git on github.
166
167* Tested with base-4.4 and ghc-7.2.1.
168
169* Use the new cabal test-suite feature.
170
171
1720.2.0.1
173
174(Released on: Wed Mar 16 15:53:50 UTC 2011)
175
176* Added laws for MonadTransControl and MonadControlIO
177
178* Bug fix: Add proper laziness to the MonadTransControl instances
179  of the lazy StateT, WriteT and RWST
180  These all failed the law: control $ \run -> run t = t
181  where t = return undefined
182
183* Add INLINABLE pragmas for most public functions
184  A simple benchmark showed some functions
185  (bracket and mask) improving by 30%.
186
187
1880.2
189
190(Released on: Wed Feb 9 12:05:26 UTC 2011)
191
192* Use RunInBase in the type of idLiftControl.
193
194* Added this NEWS file.
195
196* Only parameterize Run with t and use RankNTypes to quantify n and o
197  -liftControl :: (Monad m, Monad n, Monad o) => (Run t n o -> m a) -> t m a
198  +liftControl :: Monad m => (Run t -> m a) -> t m a
199
200  -type Run t n o = forall b. t n b -> n (t o b)
201  +type Run t = forall n o b. (Monad n, Monad o, Monad (t o)) => t n b -> n (t o b)
202
203  Bumped version from 0.1 to 0.2 to indicate this breaking change in API.
204
205* Added example of a derivation of liftControlIO.
206  Really enlightening!
207
208
2090.1
210
211(Released on: Sat Feb 5 23:36:21 UTC 2011)
212
213* Initial release
214
215This is the announcement message sent to the Haskell mailinglists:
216http://www.mail-archive.com/haskell@haskell.org/msg23278.html
217
218
219Dear all,
220
221Several attempts have been made to lift control operations (functions
222that use monadic actions as input instead of just output) through
223monad transformers:
224
225MonadCatchIO-transformers[1] provided a type class that allowed to
226overload some often used control operations (catch, block and
227unblock). Unfortunately that library was limited to those operations.
228It was not possible to use, say, alloca in a monad transformer. More
229importantly however, the library was broken as was explained[2] by
230Michael Snoyman. In response Michael created the MonadInvertIO type
231class which solved the problems. Then Anders Kaseorg created the
232monad-peel library which provided an even nicer implementation.
233
234monad-control is a rewrite of monad-peel that uses CPS style
235operations and exploits the RankNTypes language extension to simplify
236and speedup most functions. A very preliminary and not yet fully
237representative, benchmark shows that monad-control is on average about
2382.6 times faster than monad-peel:
239
240bracket:  2.4 x faster
241bracket_: 3.1 x faster
242catch:    1.8 x faster
243try:      4.0 x faster
244mask:     2.0 x faster
245
246Note that, although the package comes with a test suite that passes, I
247still consider it highly experimental.
248
249
250API DOCS:
251
252http://hackage.haskell.org/package/monad-control
253
254
255INSTALLING:
256
257$ cabal update
258$ cabal install monad-control
259
260
261TESTING:
262
263The package contains a copy of the monad-peel test suite written by
264Anders. You can perform the tests using:
265
266$ cabal unpack monad-control
267$ cd monad-control
268$ cabal configure -ftest
269$ cabal test
270
271
272BENCHMARKING:
273
274$ darcs get http://bifunctor.homelinux.net/~bas/bench-monad-peel-control/
275$ cd bench-monad-peel-control
276$ cabal configure
277$ cabal build
278$ dist/build/bench-monad-peel-control/bench-monad-peel-control
279
280
281DEVELOPING:
282
283The darcs repository will be hosted on code.haskell.org ones that
284server is back online. For the time being you can get the repository
285from:
286
287$ darcs get http://bifunctor.homelinux.net/~bas/monad-control/
288
289
290TUTORIAL:
291
292This short unpolished tutorial will explain how to lift control
293operations through monad transformers. Our goal is to lift a control
294operation like:
295
296foo ∷ M a → M a
297
298where M is some monad, into a transformed monad like 'StateT M':
299
300foo' ∷ StateT M a → StateT M a
301
302The first thing we need to do is write an instance for the
303MonadTransControl type class:
304
305class MonadTrans t ⇒ MonadTransControl t where
306  liftControl ∷ (Monad m, Monad n, Monad o)
307              ⇒ (Run t n o → m a) → t m a
308
309If you ignore the Run argument for now, you'll see that liftControl is
310identical to the 'lift' method of the MonadTrans type class:
311
312class MonadTrans t where
313    lift ∷ Monad m ⇒ m a → t m a
314
315So the instance for MonadTransControl will probably look very much
316like the instance for MonadTrans. Let's see:
317
318instance MonadTransControl (StateT s) where
319    liftControl f = StateT $ \s → liftM (\x → (x, s)) (f run)
320
321So what is this run function? Let's look at its type:
322
323type Run t n o = ∀ b. t n b → n (t o b)
324
325The run function executes a transformed monadic action 't n b' in the
326non-transformed monad 'n'. In our case the 't' will be a StateT
327computation. The only way to run a StateT computation is to give it
328some state and the only state we have lying around is the one from the
329outer computation: 's'. So let's run it on 's':
330
331instance MonadTransControl (StateT s) where
332    liftControl f =
333        StateT $ \s →
334          let run t = ... runStateT t s ...
335          in liftM (\x → (x, s)) (f run)
336
337Now that we are able to run a transformed monadic action, we're almost
338done. Look at the type of Run again. The function should leave the
339result 't o b' in the monad 'n'. This 't o b' computation should
340contain the final state after running the supplied 't n b'
341computation. In case of our StateT it should contain the final state
342s':
343
344instance MonadTransControl (StateT s) where
345    liftControl f =
346        StateT $ \s →
347          let run t = liftM (\(x, s') → StateT $ \_ → return (x, s'))
348                            (runStateT t s)
349          in liftM (\x → (x, s)) (f run)
350
351This final computation, "StateT $ \_ → return (x, s')", can later be
352used to restore the final state. Now that we have our
353MonadTransControl instance we can start using it. Recall that our goal
354was to lift "foo ∷ M a → M a" into our StateT transformer yielding the
355function "foo' ∷ StateT M a → StateT M a".
356
357To define foo', the first thing we need to do is call liftControl:
358
359foo' t = liftControl $ \run → ...
360
361This captures the current state of the StateT computation and provides
362us with the run function that allows us to run a StateT computation on
363this captured state.
364
365Now recall the type of liftControl ∷ (Run t n o → m a) → t m a. You
366can see that in place of the ... we must fill in a value of type 'm
367a'. In our case this will be a value of type 'M a'. We can construct
368such a value by calling foo. However, foo expects an argument of type
369'M a'. Fortunately we can provide one if we convert the supplied 't'
370computation of type 'StateT M a' to 'M a' using our run function of
371type ∀ b. StateT M b → M (StateT o b):
372
373foo' t = ... liftControl $ \run → foo $ run t
374
375However, note that the run function returns the final StateT
376computation inside M. So the type of the right hand side is now
377'StateT M (StateT o b)'. We would like to restore this final state. We
378can do that using join:
379
380foo' t = join $ liftControl $ \run → foo $ run t
381
382That's it! Note that because it's so common to join after a
383liftControl I provide an abstraction for it:
384
385control = join ∘ liftControl
386
387Allowing you to simplify foo' to:
388
389foo' t = control $ \run → foo $ run t
390
391Probably the most common control operations that you want to lift
392through your transformers are IO operations. Think about: bracket,
393alloca, mask, etc.. For this reason I provide the MonadControlIO type
394class:
395
396class MonadIO m ⇒ MonadControlIO m where
397  liftControlIO ∷ (RunInBase m IO → IO a) → m a
398
399Again, if you ignore the RunInBase argument, you will see that
400liftControlIO is identical to the liftIO method of the MonadIO type
401class:
402
403class Monad m ⇒ MonadIO m where
404    liftIO ∷ IO a → m a
405
406Just like Run, RunInBase allows you to run your monadic computation
407inside your base monad, which in case of liftControlIO is IO:
408
409type RunInBase m base = ∀ b. m b → base (m b)
410
411The instance for the base monad is trivial:
412
413instance MonadControlIO IO where
414    liftControlIO = idLiftControl
415
416idLiftControl directly executes f and passes it a run function which
417executes the given action and lifts the result r into the trivial
418'return r' action:
419
420idLiftControl ∷ Monad m ⇒ ((∀ b. m b → m (m b)) → m a) → m a
421idLiftControl f = f $ liftM $ \r -> return r
422
423The instances for the transformers are all identical. Let's look at
424StateT and ReaderT:
425
426instance MonadControlIO m ⇒ MonadControlIO (StateT s m) where
427    liftControlIO = liftLiftControlBase liftControlIO
428
429instance MonadControlIO m ⇒ MonadControlIO (ReaderT r m) where
430    liftControlIO = liftLiftControlBase liftControlIO
431
432The magic function is liftLiftControlBase. This function is used to
433compose two liftControl operations, the outer provided by a
434MonadTransControl instance and the inner provided as the argument:
435
436liftLiftControlBase ∷ (MonadTransControl t, Monad base, Monad m, Monad (t m))
437                    ⇒ ((RunInBase m     base → base a) →   m a)
438                    → ((RunInBase (t m) base → base a) → t m a)
439liftLiftControlBase lftCtrlBase =
440  \f → liftControl $ \run →
441         lftCtrlBase $ \runInBase →
442           f $ liftM (join ∘ lift) ∘ runInBase ∘ run
443
444Basically it captures the state of the outer monad transformer using
445liftControl. Then it captures the state of the inner monad using the
446supplied lftCtrlBase function. If you recall the identical definitions
447of the liftControlIO methods: 'liftLiftControlBase liftControlIO' you
448will see that this lftCtrlBase function is the recursive step of
449liftLiftControlBase. If you use 'liftLiftControlBase liftControlIO' in
450a stack of monad transformers a chain of liftControl operations is
451created:
452
453liftControl $ \run1 -> liftControl $ \run2 -> liftControl $ \run3 -> ...
454
455This will recurse until we hit the base monad. Then
456liftLiftControlBase will finally run f in the base monad supplying it
457with a run function that is able to run a 't m a' computation in the
458base monad. It does this by composing the run and runInBase functions.
459Note that runInBase is basically the composition: '... ∘ run3 ∘ run2'.
460
461However, just composing the run and runInBase functions is not enough.
462Namely: runInBase ∘ run ∷ ∀ b. t m b → base (m (t m b)) while we need
463to have ∀ b. t m b → base (t m b). So we need to lift the 'm (t m b)'
464computation inside t yielding: 't m (t m b)' and then join that to get
465't m b'.
466
467Now that we have our MonadControlIO instances we can start using them.
468Let's look at how to lift 'bracket' into a monad supporting
469MonadControlIO. Before we do that I define a little convenience
470function similar to 'control':
471
472controlIO = join ∘ liftControlIO
473
474Bracket just calls controlIO which captures the state of m and
475provides us with a runInIO function which allows us to run an m
476computation in IO:
477
478bracket ∷ MonadControlIO m
479        ⇒ m a → (a → m b) → (a → m c) → m c
480bracket before after thing =
481  controlIO $ \runInIO →
482    E.bracket (runInIO before)
483              (\m → runInIO $ m >>= after)
484              (\m → runInIO $ m >>= thing)
485
486I welcome any comments, questions or patches.
487
488Regards,
489
490Bas
491
492[1] http://hackage.haskell.org/package/MonadCatchIO-transformers
493[2] http://docs.yesodweb.com/blog/invertible-monads-exceptions-allocations/
494[3] http://hackage.haskell.org/package/monad-peel
495