In principle, <hask>Applicative</hask> should be a superclass of <hask>Monad</hask>, but chronologically <hask>Functor</hask> and <hask>Monad</hask> were before <hask>Applicative</hask>.

In principle, <hask>Applicative</hask> should be a superclass of <hask>Monad</hask>, but chronologically <hask>Functor</hask> and <hask>Monad</hask> were before <hask>Applicative</hask>.

−

Unfortunately, inserting <hask>Applicative</hask> between <hask>Functor</hask> and <hask>Monad</hask> in the subclass hierarchy would break a lot of existing code and thus has not been done as of today (2011).

+

Unfortunately, inserting <hask>Applicative</hask> between <hask>Functor</hask> and <hask>Monad</hask> in the subclass hierarchy would break a lot of existing code and thus has not been done as of today (2011). This is still true as of Jan 2013.

== Monad lifting ==

== Monad lifting ==

Line 129:

Line 129:

Until now, we have only considered lifting from functions to other functions. John Hughes' arrows (see [[Understanding arrows]]) are a generalization of computation that aren't functions anymore. An arrow <hask>a b c</hask> stands for a computation which transforms values of type <hask>b</hask> to values of type <hask>c</hask>. The basic primitive <hask>arr</hask>, aka <hask>pure</hask>,

Until now, we have only considered lifting from functions to other functions. John Hughes' arrows (see [[Understanding arrows]]) are a generalization of computation that aren't functions anymore. An arrow <hask>a b c</hask> stands for a computation which transforms values of type <hask>b</hask> to values of type <hask>c</hask>. The basic primitive <hask>arr</hask>, aka <hask>pure</hask>,

<haskell>

<haskell>

−

arr :: (Arrow a) => b -> c -> a b c

+

arr :: (Arrow a) => (b -> c) -> a b c

</haskell>

</haskell>

is also a lifting operation.

is also a lifting operation.

[[Category:Idioms]]

[[Category:Idioms]]

Latest revision as of 22:41, 12 August 2013

Lifting is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting.

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