In a similar way, we can define lifting operations for all containers that have "a fixed size", for example for the functions from

Double

to any value

((->)Double)

, which might be thought of as values that are varying over time (given as

Double

). The function

\t ->if t <2.0then0else2

would then represent a value which switches at time 2.0 from 0 to 2. Using lifting, such functions can be manipulated in a very high-level way. In fact, this kind of lifting operation is already defined.

(see below) functions of this monad are precisely the lifting operations we are searching for.
If the containers don't have fixed size, it's not always clear how to make lifting operations for them. The

class MonadTrans t where
lift ::Monad m => m a -> t m a -- lifts a value from the inner monad m to the transformed monad t m-- could be called lift0

lift takes the side effects of a monadic computation within the inner monad

m

and lifts them into the transformed monad

t m

. We can easily define functions which lift functions between inner monads to functions between transformed monads. Then we can perform three different lifting operations:

liftM

can be used both to transform a pure function into a function between inner monads and to a function between transformed monads, and finally lift transforms from the inner monad to the transformed monad. Because of the purity of Haskell, we can only lift "up".