Sophie

Sophie

distrib > Fedora > 15 > i386 > by-pkgid > f594880e2863b9860a125653c32b1fa6 > files > 132

ghc-transformers-devel-0.2.2.0-10.fc15.i686.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://www.cs.york.ac.uk/fp/darcs/hscolour/ -->
<title>Control/Monad/Trans/Class.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>-----------------------------------------------------------------------------</span>
<a name="line-2"></a><span class='hs-comment'>-- |</span>
<a name="line-3"></a><span class='hs-comment'>-- Module      :  Control.Monad.Trans.Class</span>
<a name="line-4"></a><span class='hs-comment'>-- Copyright   :  (c) Andy Gill 2001,</span>
<a name="line-5"></a><span class='hs-comment'>--                (c) Oregon Graduate Institute of Science and Technology, 2001</span>
<a name="line-6"></a><span class='hs-comment'>-- License     :  BSD-style (see the file LICENSE)</span>
<a name="line-7"></a><span class='hs-comment'>--</span>
<a name="line-8"></a><span class='hs-comment'>-- Maintainer  :  ross@soi.city.ac.uk</span>
<a name="line-9"></a><span class='hs-comment'>-- Stability   :  experimental</span>
<a name="line-10"></a><span class='hs-comment'>-- Portability :  portable</span>
<a name="line-11"></a><span class='hs-comment'>--</span>
<a name="line-12"></a><span class='hs-comment'>-- Classes for monad transformers.</span>
<a name="line-13"></a><span class='hs-comment'>--</span>
<a name="line-14"></a><span class='hs-comment'>-- A monad transformer makes new monad out of an existing monad, such</span>
<a name="line-15"></a><span class='hs-comment'>-- that computations of the old monad may be embedded in the new one.</span>
<a name="line-16"></a><span class='hs-comment'>-- To construct a monad with a desired set of features, one typically</span>
<a name="line-17"></a><span class='hs-comment'>-- starts with a base monad, such as @Identity@, @[]@ or 'IO', and</span>
<a name="line-18"></a><span class='hs-comment'>-- applies a sequence of monad transformers.</span>
<a name="line-19"></a><span class='hs-comment'>--</span>
<a name="line-20"></a><span class='hs-comment'>-- Most monad transformer modules include the special case of applying the</span>
<a name="line-21"></a><span class='hs-comment'>-- transformer to @Identity@.  For example, @State s@ is an abbreviation</span>
<a name="line-22"></a><span class='hs-comment'>-- for @StateT s Identity@.</span>
<a name="line-23"></a><span class='hs-comment'>--</span>
<a name="line-24"></a><span class='hs-comment'>-- Each monad transformer also comes with an operation @run@/XXX/ to</span>
<a name="line-25"></a><span class='hs-comment'>-- unwrap the transformer, exposing a computation of the inner monad.</span>
<a name="line-26"></a><span class='hs-comment'>-----------------------------------------------------------------------------</span>
<a name="line-27"></a>
<a name="line-28"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span><span class='hs-varop'>.</span><span class='hs-conid'>Trans</span><span class='hs-varop'>.</span><span class='hs-conid'>Class</span> <span class='hs-layout'>(</span>
<a name="line-29"></a>    <span class='hs-comment'>-- * Transformer class</span>
<a name="line-30"></a>    <span class='hs-conid'>MonadTrans</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span>
<a name="line-31"></a>
<a name="line-32"></a>    <span class='hs-comment'>-- * Examples</span>
<a name="line-33"></a>    <span class='hs-comment'>-- ** Parsing</span>
<a name="line-34"></a>    <span class='hs-comment'>-- $example1</span>
<a name="line-35"></a>
<a name="line-36"></a>    <span class='hs-comment'>-- ** Parsing and counting</span>
<a name="line-37"></a>    <span class='hs-comment'>-- $example2</span>
<a name="line-38"></a>  <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-39"></a>
<a name="line-40"></a><span class='hs-comment'>-- | The class of monad transformers.  Instances should satisfy the</span>
<a name="line-41"></a><span class='hs-comment'>-- following laws, which state that 'lift' is a transformer of monads:</span>
<a name="line-42"></a><span class='hs-comment'>--</span>
<a name="line-43"></a><span class='hs-comment'>-- * @'lift' . 'return' = 'return'@</span>
<a name="line-44"></a><span class='hs-comment'>--</span>
<a name="line-45"></a><span class='hs-comment'>-- * @'lift' (m &gt;&gt;= f) = 'lift' m &gt;&gt;= ('lift' . f)@</span>
<a name="line-46"></a>
<a name="line-47"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>MonadTrans</span> <span class='hs-varid'>t</span> <span class='hs-keyword'>where</span>
<a name="line-48"></a>    <span class='hs-comment'>-- | Lift a computation from the argument monad to the constructed monad.</span>
<a name="line-49"></a>    <span class='hs-varid'>lift</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Monad</span> <span class='hs-varid'>m</span> <span class='hs-keyglyph'>=&gt;</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>-&gt;</span> <span class='hs-varid'>t</span> <span class='hs-varid'>m</span> <span class='hs-varid'>a</span>
<a name="line-50"></a>
<a name="line-51"></a><span class='hs-comment'>{- $example1
<a name="line-52"></a>
<a name="line-53"></a>One might define a parsing monad by adding a state (the 'String' remaining
<a name="line-54"></a>to be parsed) to the @[]@ monad, which provides non-determinism:
<a name="line-55"></a>
<a name="line-56"></a>&gt; import Control.Monad.Trans.State
<a name="line-57"></a>&gt;
<a name="line-58"></a>&gt; type Parser = StateT String []
<a name="line-59"></a>
<a name="line-60"></a>Then @Parser@ is an instance of @MonadPlus@: monadic sequencing implements
<a name="line-61"></a>concatenation of parsers, while @mplus@ provides choice.
<a name="line-62"></a>To use parsers, we need a primitive to run a constructed parser on an
<a name="line-63"></a>input string:
<a name="line-64"></a>
<a name="line-65"></a>&gt; runParser :: Parser a -&gt; String -&gt; [a]
<a name="line-66"></a>&gt; runParser p s = [x | (x, "") &lt;- runStateT p s]
<a name="line-67"></a>
<a name="line-68"></a>Finally, we need a primitive parser that matches a single character,
<a name="line-69"></a>from which arbitrarily complex parsers may be constructed:
<a name="line-70"></a>
<a name="line-71"></a>&gt; item :: Parser Char
<a name="line-72"></a>&gt; item = do
<a name="line-73"></a>&gt;     c:cs &lt;- get
<a name="line-74"></a>&gt;     put cs
<a name="line-75"></a>&gt;     return c
<a name="line-76"></a>
<a name="line-77"></a>In this example we use the operations @get@ and @put@ from
<a name="line-78"></a>"Control.Monad.Trans.State", which are defined only for monads that are
<a name="line-79"></a>applications of @StateT@.  Alternatively one could use monad classes
<a name="line-80"></a>from other packages, which contain methods @get@ and @put@ with types
<a name="line-81"></a>generalized over all suitable monads.
<a name="line-82"></a>-}</span>
<a name="line-83"></a>
<a name="line-84"></a><span class='hs-comment'>{- $example2
<a name="line-85"></a>
<a name="line-86"></a>We can define a parser that also counts by adding a @WriterT@ transformer:
<a name="line-87"></a>
<a name="line-88"></a>&gt; import Control.Monad.Trans.Class
<a name="line-89"></a>&gt; import Control.Monad.Trans.State
<a name="line-90"></a>&gt; import Control.Monad.Trans.Writer
<a name="line-91"></a>&gt; import Data.Monoid
<a name="line-92"></a>&gt;
<a name="line-93"></a>&gt; type Parser = WriterT (Sum Int) (StateT String [])
<a name="line-94"></a>
<a name="line-95"></a>The function that applies a parser must now unwrap each of the monad
<a name="line-96"></a>transformers in turn:
<a name="line-97"></a>
<a name="line-98"></a>&gt; runParser :: Parser a -&gt; String -&gt; [(a, Int)]
<a name="line-99"></a>&gt; runParser p s = [(x, n) | ((x, Sum n), "") &lt;- runStateT (runWriterT p) s]
<a name="line-100"></a>
<a name="line-101"></a>To define @item@ parser, we need to lift the @StateT@ operations through
<a name="line-102"></a>the @WriterT@ transformers.
<a name="line-103"></a>
<a name="line-104"></a>&gt; item :: Parser Char
<a name="line-105"></a>&gt; item = do
<a name="line-106"></a>&gt;     c:cs &lt;- lift get
<a name="line-107"></a>&gt;     lift (put cs)
<a name="line-108"></a>&gt;     return c
<a name="line-109"></a>
<a name="line-110"></a>In this case, we were able to do this with 'lift', but operations with
<a name="line-111"></a>more complex types require special lifting functions, which are provided
<a name="line-112"></a>by monad transformers for which they can be implemented.  If you use
<a name="line-113"></a>one of packages of monad classes, this lifting is handled automatically
<a name="line-114"></a>by the instances of the classes, and you need only use the generalized
<a name="line-115"></a>methods @get@ and @put@.
<a name="line-116"></a>
<a name="line-117"></a>We can also define a primitive using the Writer:
<a name="line-118"></a>
<a name="line-119"></a>&gt; tick :: Parser ()
<a name="line-120"></a>&gt; tick = tell (Sum 1)
<a name="line-121"></a>
<a name="line-122"></a>Then the parser will keep track of how many @tick@s it executes.
<a name="line-123"></a>-}</span>
</pre></body>
</html>