## 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 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.