Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[17]

£ то

св а: =з

A transformer version of the Reader monad, called ReaderT, exists which adds a monad type constructor as an addition parameter. ReaderTr m a is the type of values of the combined monad in which Reader is the base monad and m is the inner monad. ReaderTr m is an instance of the monad class, and the runReaderT::(r -> m a) function performs a computation in the combined monad and returns a result of type m a.

Using the transformer versions of the monads, we can produce combined monads very simply. ReaderTr IO is a combined Reader+IO monad. We can also generate the non-transformer version of a monad from the transformer version by applying it to the Identity monad. So ReaderTr Identity is the same monad as Reader r.

If your code produces kind errors during compilation, it means that you are not using the type cosntructors properly. Make sure that you have supplied the correct number of parameters to the type constructors and that you have not left out any parenthesis in complex type expressions.

3.3.2. Lifting

When using combined monads created by the monad transformers, we avoid having to explicitly manage the inner monad types, resulting in clearer, simpler code. Instead of creating additional do-blocks within the computation to manipulate values in the inner monad type, we can use lifting operations to bring functions from the inner monad into the combined monad.

Recall the liftM family of functions which are used to lift non-monadic functions into a monad. Each monad transformer provides a lift function that is used to lift a monadic computation into a combined monad. Many transformers also provide a liftIO function, which is a version of lift that is optimized for lifting computations in the IO monad. To see this in action, we will continue to develop our previous example in the Continuation monad.

Code available in example21.hs

fun :: IO String

fun = ("runContT1 return) $ do

n <- liftIO (readLn::IO Int)

str <- callCC $ \exit1 -> do- define "exit1"

when (n < 10) (exit1 (show n)) let ns = map digitToInt (show (n "div1 2)) n <- callCC $ \exit2 -> do - define "exit2" when ((length ns) < 3) (exit2 (length ns))

when ((length ns) < 5) $ do liftIO $ putStrLn "Enter a number:"

x <- liftIO (readLn::IO Int) exit2 x

when ((length ns) < 7) $ do let ns = map intToDigit (reverse ns)

exitl (dropWhile (==0) ns) -

escape 2 levels

return $ sum ns

ФП 02005-03 01

Пист 57


return $ "(ns = return $ "Answer:

++ (show ns) ++ ") ++ str

++ (show n)

Compare this function using ContT, the transformer version of Cont, with the original version to see how unobtrusive the changes become when using the monad transformer.

Nested monads from example 19

fun = do n <- (readLn::IO Int)

return $ ("runCont" id) $ do str <- callCC $ \exitl -> do when (n < l0) (exitl (show n)) let ns = map digitToInt (show (n "div" 2)) n <- callCC $ \exit2 -> do

when ((length ns) < 3) (exit2 (length ns)) when ((length ns) < 5) (exit2 n) when ((length ns) < 7) $ do

let ns = map intToDigit (reverse ns) exitl (dropWhile (==0) ns) return $ sum ns return $ "(ns = " ++ (show ns) ++ ") " ++ (show n) return $ "Answer: " ++ str

Monads combined with a transformer from example 21

fun = ("runContT" return) $ do

n <- liftIO (readLn::IO Int) str <- callCC $ \exitl -> do when (n < l0) (exitl (show n)) let ns = map digitToInt (show (n "div" 2)) n <- callCC $ \exit2 -> do

when ((length ns) < 3) (exit2 (length ns)) when ((length ns) < 5) $ do

liftIO $ putStrLn "Enter a number:" x <- liftIO (readLn::IO Int) exit2 x when ((length ns) < 7) $ do

let ns = map intToDigit (reverse ns) exitl (dropWhile (==0) ns) return $ sum ns return $ "(ns = " ++ (show ns) ++ ") " ++ (show n) return $ "Answer: " ++ str

The impact of adding the I/O in the middle of the computation is narrowly confined when using the monad transformer. Contrast this with the changes required to achieve the same result using a manually combined monad.

ФП 02005-03 01

Лист 58

№ докум.

Копиоова Фоомат


3.4. Standard monad transformers

Haskells base libraries provide support for monad transformers in the form of classes which represent monad transformers and special transformer versions of standard monads.

3.4.1.The MonadTrans and MonadIO classes

The MonadTrans class is defined in Control.Monad.Trans and provides the single function lift. The lift function lifts a monadic computation in the inner monad into the combined monad.

class MonadTrans t where

lift :: (Monad m) => m a -> t m a

Monads which provide optimized support for lifting IO operations are defined as members of the MonadIO class, which defines the liftIO function.

class (Monad m) => MonadIO m where liftIO :: IO a -> m a

3.4.2.Transformer versions of standard monads

The standard monads of the monad template library all have transformer versions which are defined consistently with their non-transformer versions. However, it is not the case the all monad transformers apply the same transformation. We have seen that the ContT transformer turns continuations of the form (a->r)->r into continuations of the form (a->m r)->m r. The StateT transformer is different. It turns state transformer functions of the form s->(a,s) into state transformer functions of the form s->m (a,s). In general, there is no magic formula to create a transformer version of a monad - the form of each transformer depends on what makes sense in the context of its non-transformer type.

Standard

Transformer

Version

Writer!

Original Type

Combined Type

Either e a

s -> (a,s)

r -> a

m (Either e a)

s -> m (a,s)

r -> m a

m (a,w)

(a -> r) -> r

(a -> m r) -> m

ФП 02005-03 01

Пист 59

№ докум.

Копиоова Формат



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25]