packages feed

transformers-free (empty) → 1.0.0

raw patch · 4 files changed

+306/−0 lines, 4 filesdep +basedep +transformerssetup-changed

Dependencies added: base, transformers

Files

+ Control/Monad/Trans/Free.hs view
@@ -0,0 +1,255 @@+{-|+    Free monads build syntax trees.  See the example sections for details.++    A free monad over a functor resembles a list of that functor:++    * 'return' behaves like @[]@ by not using the functor at all++    * 'wrap' behaves like @(:)@ by prepending another layer of the functor++    * 'liftF' behaves like @singleton@ by creating a list from a single layer of+      the functor.+-}++module Control.Monad.Trans.Free (+    -- * Usage+    -- $usage++    -- * Free monad+    Free,+    FreeF(..),+    runFree,++    -- * Free monad transformer+    FreeT(..),++    -- * Free monad operations+    wrap,+    liftF++    -- * Free monad example+    -- $freeexample++    -- * Free monad transformer example+    -- $freetexample+    ) where++import Control.Applicative+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Data.Functor.Identity++{- $usage+    You can assemble values of type @Free f a@ or @FreeT f m a@ by hand using+    the smart constructors 'return' (from @Control.Monad@) and 'wrap':++> return ::              r  -> FreeT f m r+> wrap   :: f (FreeT f m r) -> FreeT f m r++    Use 'runFree' to deconstruct values of type @Free f r@:++> case runFree x of+>     Pure a -> ...+>     Free w -> ...++    Use 'runFreeT' to deconstruct values of type @FreeT f m r@ and bind the+    result in the base monad @m@.  You can then pattern match against the bound+    value:++> do x <- runFreeT f+>    case x of+>        Pure a -> ...+>        Free w -> ...+-}++-- | The signature for 'Free'+data FreeF f a x = Pure a | Free (f x)++{-|+    A free monad transformer alternates nesting the base monad @m@ and the base+    functor @f@, terminating with a value of type @a@.++    * @f@ - The functor that generates the free monad transformer++    * @m@ - The base monad++    * @a@ - The return value+-}+newtype FreeT f m a = FreeT { runFreeT :: m (FreeF f a (FreeT f m a)) }++instance (Functor f, Monad m) => Functor (FreeT f m) where+    fmap = liftM++instance (Functor f, Monad m) => Applicative (FreeT f m) where+    pure  = return+    (<*>) = ap++instance (Functor f, Monad m) => Monad (FreeT f m) where+    return  = FreeT . return . Pure+    m >>= f = FreeT $ do+        x <- runFreeT m+        runFreeT $ case x of+            Pure a -> f a+            Free w -> wrap $ fmap (>>= f) w++instance MonadTrans (FreeT f) where+    lift = FreeT . liftM Pure++instance (Functor f, MonadIO m) => MonadIO (FreeT f m) where+    liftIO = lift . liftIO ++-- | Prepend one layer of the functor to the free monad+wrap :: (Monad m) => f (FreeT f m a) -> FreeT f m a+wrap = FreeT . return . Free++-- | Convert one layer of a functor into an operation in the free monad+liftF :: (Functor f, Monad m) => f a -> FreeT f m a+liftF x = wrap $ fmap return x++{-|+    @Free f a@ is a list of nested @f@s terminating with a return value of type+    @a@.++    * @f@ - The functor that generates the free monad++    * @a@ - The return value+-}+type Free f = FreeT f Identity++-- | Observation function that exposes the next step+runFree :: Free f r -> FreeF f r (Free f r)+runFree = runIdentity . runFreeT++{- $freeexample+    To create a syntax tree, first define the signature for a single step in the+    syntax tree:++> data TeletypeF next = PutString String next | GetString (String -> next)++    ... then make the signature a 'Functor', where 'fmap' applies the given+    function to the @next@ step:++> instance Functor TeletypeF where+>     fmap f (PutString str x) = PutString str (f x)+>     fmap f (GetString     k) = GetString (f . k)++    The 'Free' type constructor generates the corresponding syntax tree from+    this signature:++> type Teletype a = Free TeletypeF a++    'liftF' creates primitive operations for building the syntax tree:++> putString :: String -> Teletype ()+> putString str = liftF $ PutString str ()+>+> getString :: Teletype String+> getString = liftF $ GetString id++    The syntax tree is automatically a monad, so you can assemble these+    operations into larger syntax trees using @do@ notation:++> echo :: Teletype a+> echo = forever $ do+>     str <- getString+>     putString str++    ... which is equivalent to the following hand-written syntax tree:++> echo' :: Teletype r+> echo' = wrap $ GetString $ \str -> wrap $ PutString str echo'++    You then interpret the syntax tree using 'runFree' to inspect the tree one+    step at a time.++> runIO :: Teletype a -> IO a+> runIO t = case runFree t of+>     Pure r -> return r+>     Free (PutString str t') -> do+>         putStrLn str+>         runIO t'+>     Free (GetString     k ) -> do+>         str <- getLine+>         runIO (k str)++>>> runIO echo+A<Enter>+A+Test<Enter>+Test+...++    You can write pure interpreters, too:++> runPure :: Teletype a -> [String] -> [String]+> runPure t strs = case runFree t of+>     Pure r -> []+>     Free (PutString str t') -> str:runPure t' strs+>     Free (GetString     k ) -> case strs of+>         []        -> []+>         str:strs' -> runPure (k str) strs'++>>> runPure echo ["A", "Test"]+["A","Test"]+-}++{- $freetexample+    The Free monad transformer 'FreeT' lets us invoke the base monad to build+    the syntax tree.  For example, you can use 'IO' to prompt the user to select+    each step of the syntax tree using the following monad:++> FreeT TeletypeF IO r++    Our original primitives actually had the following more polymorphic types,+    so you can reuse them:++> putString :: (Monad m) => String -> FreeT TeletypeF m ()+> putString str = liftF $ PutString str ()+>+> getString :: (Monad m) => FreeT TeletypeF m String+> getString = liftF $ GetString id++    Now the user can build the syntax tree from the command line:++> prompt :: FreeT TeletypeF IO ()+> prompt = do+>     lift $ putStrLn "Supply the next step:+>     cmd <- lift getLine+>     case cmd of+>         "forward" -> do+>             str <- getString+>             putString str+>             prompt+>         "greet" -> do+>             putString "Hello, world!"+>             prompt+>         _ -> return ()++    You can then run the syntax tree as the user builds it:++> -- The 'FreeT' version of 'runIO'+> runTIO :: FreeT TeletypeF IO r -> IO r+> runTIO t = do+>     x <- runFreeT t+>     case x of+>         Pure r -> return r+>         Free (PutString str t') -> do+>             putStrLn str+>             runTIO t'+>         Free (GetString k) -> do+>             str <- getLine+>             runTIO (k str)++>>> runTIO prompt+Supply the next step:+greet<Enter>+Hello, world!+Supply the next step:+forward<Enter>+test<Enter>+test+Supply the next step:+quit<Enter>++-}
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2012, Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:+    * Redistributions of source code must retain the above copyright notice,+      this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright notice,+      this list of conditions and the following disclaimer in the documentation+      and/or other materials provided with the distribution.+    * Neither the name of Gabriel Gonzalez nor the names of other contributors+      may be used to endorse or promote products derived from this software+      without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ transformers-free.cabal view
@@ -0,0 +1,25 @@+Name: transformers-free+Version: 1.0.0+Cabal-Version: >=1.14.0+Build-Type: Simple+License: BSD3+License-File: LICENSE+Copyright: 2012 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Stability: Experimental+Bug-Reports:+    https://github.com/Gabriel439/Haskell-Transformers-Free-Library/issues+Synopsis: Free monad transformers+Description: This library generalizes free monads to free monad transformers.+Category: Control+Tested-With: GHC ==7.0.3+Source-Repository head+    Type: git+    Location: https://github.com/Gabriel439/Haskell-Transformers-Free-Library++Library+    Build-Depends: base >= 2 && < 6, transformers >= 0.2+    Exposed-Modules: Control.Monad.Trans.Free+    GHC-Options: -O2+    Default-Language: Haskell98