Reader Monad. Added Haddock documentation. Converted the existing module documentatio...
authorAndriy Palamarchuk <apa3a@yahoo.com>
Wed, 27 Jun 2007 18:05:20 +0000 (18:05 +0000)
committerAndriy Palamarchuk <apa3a@yahoo.com>
Wed, 27 Jun 2007 18:05:20 +0000 (18:05 +0000)
Control/Monad/Reader.hs
Control/Monad/Reader/Class.hs

index 3959170..5262816 100644 (file)
@@ -1,24 +1,41 @@
 {-# OPTIONS -fallow-undecidable-instances #-}
--- Search for -fallow-undecidable-instances to see why this is needed
------------------------------------------------------------------------------
--- |
--- Module      :  Control.Monad.Reader
--- Copyright   :  (c) Andy Gill 2001,
---                (c) Oregon Graduate Institute of Science and Technology, 2001
--- License     :  BSD-style (see the file libraries/base/LICENSE)
---
--- Maintainer  :  libraries@haskell.org
--- Stability   :  experimental
--- Portability :  non-portable (multi-param classes, functional dependencies)
---
--- Declaration of the MonadReader class
---
---      Inspired by the paper
---      /Functional Programming with Overloading and
---          Higher-Order Polymorphism/,
---        Mark P Jones (<http://www.cse.ogi.edu/~mpj/>)
---          Advanced School of Functional Programming, 1995.
------------------------------------------------------------------------------
+{- |
+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 libraries/base/LICENSE)
+
+Maintainer  :  libraries@haskell.org
+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.
+
+[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://www.cse.ogi.edu/~mpj/>)
+    Advanced School of Functional Programming, 1995.
+-}
 
 module Control.Monad.Reader (
     module Control.Monad.Reader.Class,
@@ -31,6 +48,14 @@ module Control.Monad.Reader (
     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
@@ -50,15 +75,33 @@ instance MonadReader r ((->) r) where
     ask       = id
     local f m = m . f
 
--- ---------------------------------------------------------------------------
--- Our parameterizable reader monad
+{- |
+The parameterizable reader monad.
+
+The @return@ function creates a @Reader@ that ignores the environment,
+and produces the given value.
 
-newtype Reader r a = Reader { runReader :: r -> a }
+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.
+-}
+newtype Reader r a = Reader {
+    {- |
+    Runs @Reader@ and extracts the final value from it.
+    To extract the value apply @(runReader reader)@ to an environment value.  
+    Parameters:
+
+    * A @Reader@ to run.
+
+    * An initial environment.
+    -}
+    runReader :: r -> a
+}
 
 mapReader :: (a -> b) -> Reader r a -> Reader r b
 mapReader f m = Reader $ f . runReader m
 
--- This is a more general version of local.
+-- | A more general version of 'local'.
 
 withReader :: (r' -> r) -> Reader r a -> Reader r' a
 withReader f m = Reader $ runReader m . f
@@ -77,9 +120,10 @@ instance MonadReader r (Reader r) where
     ask       = Reader id
     local f m = Reader $ runReader m . f
 
--- ---------------------------------------------------------------------------
--- Our parameterizable reader monad, with an inner monad
-
+{- |
+The reader monad transformer.
+Can be used to add environment reading functionality to other monads.
+-}
 newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
 
 mapReaderT :: (m a -> n b) -> ReaderT w m a -> ReaderT w n b
@@ -142,3 +186,73 @@ instance (MonadWriter w m) => MonadWriter w (ReaderT r m) where
     listen m = ReaderT $ \w -> listen (runReaderT m w)
     pass   m = ReaderT $ \w -> pass   (runReaderT m w)
 
+{- $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"
+-}
index 6c9e99e..7d961ba 100644 (file)
@@ -1,40 +1,72 @@
 {-# OPTIONS -fallow-undecidable-instances #-}
--- Search for -fallow-undecidable-instances to see why this is needed
------------------------------------------------------------------------------
--- |
--- Module      :  Control.Monad.Reader.Class
--- Copyright   :  (c) Andy Gill 2001,
---                (c) Oregon Graduate Institute of Science and Technology, 2001
--- License     :  BSD-style (see the file libraries/base/LICENSE)
---
--- Maintainer  :  libraries@haskell.org
--- Stability   :  experimental
--- Portability :  non-portable (multi-param classes, functional dependencies)
---
--- MonadReader class.
---
---      Inspired by the paper
---      /Functional Programming with Overloading and
---          Higher-Order Polymorphism/,
---        Mark P Jones (<http://www.cse.ogi.edu/~mpj/>)
---          Advanced School of Functional Programming, 1995.
------------------------------------------------------------------------------
+{- |
+Module      :  Control.Monad.Reader.Class
+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 libraries/base/LICENSE)
+
+Maintainer  :  libraries@haskell.org
+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.
+
+[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://www.cse.ogi.edu/~mpj/>)
+    Advanced School of Functional Programming, 1995.
+-}
 
 module Control.Monad.Reader.Class (
     MonadReader(..),
     asks,
     ) where
 
--- ----------------------------------------------------------------------------
--- class MonadReader
---  asks for the internal (non-mutable) state.
-
+{- |
+See examples in "Control.Monad.Reader".
+Note, the partially applied function type @(->) r@ is a simple reader monad.
+See the @instance@ declaration below.
+-}
 class (Monad m) => MonadReader r m | m -> r where
+    -- | Retrieves the monad environment.
     ask   :: m r
+    {- | Executes a computation in a modified environment. Parameters:
+
+    * The function to modify the environment.
+
+    * @Reader@ to run.
+
+    * The resulting @Reader@.
+    -}
     local :: (r -> r) -> m a -> m a
 
--- This allows you to provide a projection function.
+{- |
+Retrieves a function of the current environment. Parameters:
+
+* The selector function to apply to the environment.
 
+See an example in "Control.Monad.Reader".
+-}
 asks :: (MonadReader r m) => (r -> a) -> m a
 asks f = do
     r <- ask