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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
{- |
Module : Control.Monad.Reader
Copyright : (c) Andy Gill 2001,
(c) Oregon Graduate Institute of Science and Technology 2001,
(c) Jeff Newbern 2003-2007,
(c) Andriy Palamarchuk 2007
License : BSD-style (see the file LICENSE)
Maintainer : ross@soi.city.ac.uk
Stability : experimental
Portability : non-portable (type families)
[Computation type:] Computations which read values from a shared environment.
[Binding strategy:] Monad values are functions from the environment to a value.
The bound function is applied to the bound value, and both have access
to the shared environment.
[Useful for:] Maintaining variable bindings, or other shared environment.
[Zero and plus:] None.
[Example type:] @'Reader' [(String,Value)] a@
The 'Reader' monad (also called the Environment monad).
Represents a computation, which can read values from
a shared environment, pass values from function to function,
and execute sub-computations in a modified environment.
Using 'Reader' monad for such computations is often clearer and easier
than using the 'Control.Monad.State.State' monad.
Inspired by the paper
/Functional Programming with Overloading and
Higher-Order Polymorphism/,
Mark P Jones (<http://web.cecs.pdx.edu/~mpj/>)
Advanced School of Functional Programming, 1995.
-}
module Control.Monad.Reader (
-- * MonadReader class
MonadReader(..),
asks,
-- * The Reader monad
Reader,
runReader,
mapReader,
withReader,
-- * The ReaderT monad transformer
ReaderT(..),
mapReaderT,
withReaderT,
module Control.Monad,
module Control.Monad.Fix,
module Control.Monad.Trans,
-- * Example 1: Simple Reader Usage
-- $simpleReaderExample
-- * Example 2: Modifying Reader Content With @local@
-- $localExample
-- * Example 3: @ReaderT@ Monad Transformer
-- $ReaderTExample
) where
import Control.Monad.Reader.Class
import Control.Monad.Trans.Reader (
Reader, runReader, mapReader, withReader,
ReaderT(..), mapReaderT, withReaderT)
import Control.Monad.Trans
import Control.Monad
import Control.Monad.Fix
{- $simpleReaderExample
In this example the @Reader@ monad provides access to variable bindings.
Bindings are a @Map@ of integer variables.
The variable @count@ contains number of variables in the bindings.
You can see how to run a Reader monad and retrieve data from it
with 'runReader', how to access the Reader data with 'ask' and 'asks'.
> type Bindings = Map String Int;
>
>-- Returns True if the "count" variable contains correct bindings size.
>isCountCorrect :: Bindings -> Bool
>isCountCorrect bindings = runReader calc_isCountCorrect bindings
>
>-- The Reader monad, which implements this complicated check.
>calc_isCountCorrect :: Reader Bindings Bool
>calc_isCountCorrect = do
> count <- asks (lookupVar "count")
> bindings <- ask
> return (count == (Map.size bindings))
>
>-- The selector function to use with 'asks'.
>-- Returns value of the variable with specified name.
>lookupVar :: String -> Bindings -> Int
>lookupVar name bindings = fromJust (Map.lookup name bindings)
>
>sampleBindings = Map.fromList [("count",3), ("1",1), ("b",2)]
>
>main = do
> putStr $ "Count is correct for bindings " ++ (show sampleBindings) ++ ": ";
> putStrLn $ show (isCountCorrect sampleBindings);
-}
{- $localExample
Shows how to modify Reader content with 'local'.
>calculateContentLen :: Reader String Int
>calculateContentLen = do
> content <- ask
> return (length content);
>
>-- Calls calculateContentLen after adding a prefix to the Reader content.
>calculateModifiedContentLen :: Reader String Int
>calculateModifiedContentLen = local ("Prefix " ++) calculateContentLen
>
>main = do
> let s = "12345";
> let modifiedLen = runReader calculateModifiedContentLen s
> let len = runReader calculateContentLen s
> putStrLn $ "Modified 's' length: " ++ (show modifiedLen)
> putStrLn $ "Original 's' length: " ++ (show len)
-}
{- $ReaderTExample
Now you are thinking: 'Wow, what a great monad! I wish I could use
Reader functionality in MyFavoriteComplexMonad!'. Don't worry.
This can be easy done with the 'ReaderT' monad transformer.
This example shows how to combine @ReaderT@ with the IO monad.
>-- The Reader/IO combined monad, where Reader stores a string.
>printReaderContent :: ReaderT String IO ()
>printReaderContent = do
> content <- ask
> liftIO $ putStrLn ("The Reader Content: " ++ content)
>
>main = do
> runReaderT printReaderContent "Some Content"
-}
|