```{-# OPTIONS_GHC -fno-warn-orphans #-}	    -- Temporary, I hope.  SLPJ Aug08
{-# OPTIONS -fallow-undecidable-instances #-}
{- |
Copyright   :  (c) Andy Gill 2001,
(c) Oregon Graduate Institute of Science and Technology 2001,
(c) Jeff Newbern 2003-2007,
(c) Andriy Palamarchuk 2007

Stability   :  experimental
Portability :  non-portable (multi-param classes, functional dependencies)

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

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.

Inspired by the paper
Higher-Order Polymorphism/,
Mark P Jones (<http://web.cecs.pdx.edu/~mpj/>)
Advanced School of Functional Programming, 1995.
-}

-- * Example 1: Simple Reader Usage

-- * Example 2: Modifying Reader Content With @local@
-- \$localExample

) where

-- ----------------------------------------------------------------------------

local f m = m . f

{- |

The @return@ function creates a @Reader@ that ignores the environment,
and produces the given value.

The binding operator @>>=@ produces a @Reader@ that uses the environment
to extract the value its left-hand side,
and then applies the bound function to that value in the same environment.
-}
{- |
Runs @Reader@ and extracts the final value from it.
Parameters:

* An initial environment.
-}
}

-- | A more general version of 'local'.

fmap f m = Reader \$ \r -> f (runReader m r)

return a = Reader \$ \_ -> a

mfix f = Reader \$ \r -> let a = runReader (f a) r in a

{- |
-}

mapReaderT :: (m a -> n b) -> ReaderT w m a -> ReaderT w n b

fmap f m = ReaderT \$ \r -> do
return (f a)

return a = ReaderT \$ \_ -> return a
m >>= k  = ReaderT \$ \r -> do
fail msg = ReaderT \$ \_ -> fail msg

mzero       = ReaderT \$ \_ -> mzero

mfix f = ReaderT \$ \r -> mfix \$ \a -> runReaderT (f a) r

local f m = ReaderT \$ \r -> runReaderT m (f r)

-- ---------------------------------------------------------------------------
-- Instances for other mtl transformers

lift m = ReaderT \$ \_ -> m

liftIO = lift . liftIO

callCC f = ReaderT \$ \r ->
callCC \$ \c ->

throwError       = lift . throwError
`catchError` \e -> runReaderT (h e) r

-- Needs -fallow-undecidable-instances
get = lift get
put = lift . put

-- This instance needs -fallow-undecidable-instances, because
-- it does not satisfy the coverage condition
tell     = lift . tell

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

> type Bindings = Map String Int;
>
>-- Returns True if the "count" variable contains correct bindings size.
>isCountCorrect :: Bindings -> Bool
>isCountCorrect bindings = runReader calc_isCountCorrect bindings
>
>calc_isCountCorrect = do
>    count <- asks (lookupVar "count")
>    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 = do
>    return (length content);
>
>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)
-}

Now you are thinking: 'Wow, what a great monad! I wish I could use