streamly-0.9.0: docs/User/Explanatory/monad-transformers.md
# Monad Transformers
In the stream tutorials we mostly used streams in the IO monad. In
general, the type `SerialT` is a monad transformer, @SerialT m a@
represents a stream of values of type 'a' in some underlying monad
'm'. For example, @SerialT IO Int@ is a stream of 'Int' in 'IO'
monad. Similarly, `SerialT Identity Int` would be a pure stream
equivalent to `[a]`.
Similarly we have monad transformer types for other stream types as well
viz. 'WSerialT', 'AsyncT', 'WAsyncT' and 'ParallelT'.
To lift a value from an underlying monad in a monad transformer stack into a
singleton stream use 'lift' and to lift from an IO action use 'liftIO'.
```
>>> import Control.Monad.IO.Class (liftIO)
>>> Stream.drain $ liftIO $ putStrLn "Hello world!"
Hello world!
>>> import Control.Monad.Trans.Class (MonadTrans(lift))
>>> Stream.drain $ lift $ putStrLn "Hello world!"
Hello world!
```
## Using Monad Transformers
Common monad transformers can be used with streamly serial streams, without any
issues. `ReaderT` can be used with concurrent streams as well without any
issues.
The semantics of monads other than `ReaderT` with concurrent streams are
not yet finalized and will change in future, therefore, as of now they are not
recommended to be used with concurrent streams.
## Ordering of Monad Transformers
In most cases it is a good idea to keep streamly as the top level monad.
[This
example](https://github.com/composewell/streamly-examples/blob/master/examples/ControlFlow.hs)
demonstrates how various control flow modifying monads can be combined
with streamly stream monads.
## State Sharing
### Serial Applications
Read only global state can always be shared using the `Reader` monad.
Read-write global state can be shared either using an `IORef` in the `Reader`
monad or using the `State` monad.
See `AcidRain.hs` example for a usage of `StateT` in the serially executing
portion of the program.
### Concurrent Applications
The current recommended method for sharing modifiable global state across
concurrent tasks is to put the shared state inside an `IORef` in a `Reader`
monad or just share the `IORef` by passing it to the required functions. The
`IORef` can be updated atomically using `atomicModifyIORef`.
The `CirclingSquare.hs` example shares an `IORef` across parallel tasks.
## See also
* [Examples of control flow monads with Streamly](https://github.com/composewell/streamly-examples/blob/master/examples/ControlFlow.hs)