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


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




[16]

£ то

The code introduced in example 18 followed the nesting pattern: reading a number from the command line in the IO monad, passing that number to a computation in the Continuation monad to produce a string, and then writing the string back in the IO monad. The computations in the IO monad arent restricted to reading from the command line and writing strings; they can be arbitrarily complex. Likewise, the inner computation can be arbitrarily complex as well. As long as the inner computation does not depend on the functionality of the outer monad, it can be safely nested within the outer monad, as illustrated in this variation on example 18 which reads the value from stdin instead of using a command line argument:

Code available in example19.hs

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

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

this is an IO monad block this is a Cont monad block

3) 5) 7)

(exit2 (length ns)) (exit2 n)

$ do let ns = map intToDigit (reverse

exitl (dropWhile (==0) ns)

return $ sum ns return $ "(ns = " ++ (show ns) ++ ") return $ "Answer: " ++ str

++ (show n)

3.2.2. Combined Monads

What about computations with more complicated structure? If the nesting pattern cannot be used, we need a way to combine the attributes of two or more monads in a single computation. This is accomplished by doing computations within a monad in which the values are themselves monadic values in another monad. For example, we might perform computations in the Continuation monad of type Cont (IO String) a if we need to perform I/O within the computation in the Continuation monad. We could use a monad of type State (Either Err a) a to combine the features of the State and Error monads in a single computation.

Consider a slight modification to our example in which we perform the same I/O at the beginning, but we may require additional input in the middle of the computation in the Continuation monad. In this case, we will allow the user to specify part of the output value when the input value is within a certain range. Because the I/O depends on part of the computation in the Continuation monad and part of the computation in the Continuation monad depends on the result of the I/O, we cannot use the nested monad pattern.

ФП 02005-03 01

Лист 54

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


Instead, we make the computation in the Continuation monad use values from the IO monad. What used to be Int and String values are now of type IO Int and IO String. We cant extract values from the IO monad - its a one-way monad - so we may need to nest little do-blocks of the IO monad within the Continuation monad to manipulate the values. We use a helper function toIO to make it clearer when we are creating values in the IO monad nested within the Continuation monad.

Code available in example20.hs

toIO :: a -> IO a toIO x = return x

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

-- this is an IO monad block

convert :: convert n

Int -> IO String

= ("runCont1 id) $ do-- this is a Cont monad block

str <- callCC $ \exit1 -> do -- str has type IO String when (n < 10) (exitl $ toIO (show n)) let ns = map digitToInt (show (n "div" 2)) n <- callCC $ \exit2 -> do - n has type IO Int

3) (exit2 (toIO (length ns))) 5) (exit2 $ do putStrLn "Enter a

when ((length ns) when ((length ns)

number:"

(reverse ns) ns)

x <- (readLn::IO Int) return x)

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

exitl $ toIO (dropWhile (==0)

return (toIO (sum ns)) return $ do num <- n -- this is an IO monad block

return $ "(ns = " ++ (show ns) ++ ") " ++ (show

return $ do s <- str -- this is an IO monad block return $ "Answer: " ++ s

Even this trivial example has gotten confusing and ugly when we tried to combine different monads in the same computation. It works, but it isnt pretty. Comparing the code side-by-side shows the degree to which the manual monad combination strategy pollutes the code.

Nested monads from example 19

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

return $ ("runCont" id) $ do str <- callCC $ \exitl -> do when (n < 10) (exit1 (show n))

ФП 02005-03 01

№ докум.

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


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

Manually combined monads from example 20

convert n =

("runCont" id) $ do

str <- callCC $ \exitl -> do

when (n < 10) (exitl $ toIO (show n)) let ns = map digitToInt (show (n "div" n <- callCC $ \exit2 -> do

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

let ns = map intToDigit (reverse ns) exitl $ toIO (dropWhile (==0) ns) return (toIO (sum ns)) return $ do num <- n

return $ "(ns = " ++ (show ns) ++ ") " ++ (show

return $ do s <- str return $

"Answer:

3.3. Monad transformers

Monad transformers are special variants of standard monads that facilitate the combining of monads. Their type constructors are parameterized over a monad type constructor, and they produce combined monadic types.

3.3.1. Transformer type constructors

Type constructors play a fundamental role in Haskells monad support. Recall that Reader r a is the type of values of type a within a Reader monad with environment of type r. The type constructor Reader r is an instance of the Monad class, and the runReader::(r->a) function performs a computation in the Reader monad and returns the result of type a.

ФП 02005-03 01

Лист 56

№ докум.

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



[стр.Начало] [стр.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]