packages feed

continue (empty) → 0.1.0

raw patch · 8 files changed

+527/−0 lines, 8 filesdep +basedep +bifunctorsdep +monad-controlsetup-changed

Dependencies added: base, bifunctors, monad-control, mtl, semigroupoids, transformers, transformers-base

Files

+ Control/Continue.hs view
@@ -0,0 +1,24 @@+-- |+-- Module:     Control.Continue+-- Copyright:  (c) 2012 Ertugrul Soeylemez+-- License:    BSD3+-- Maintainer: Ertugrul Soeylemez <es@ertes.de>+--+-- Proxy to the various modules of the continue package.++module Control.Continue+    ( -- * Continue modules+      module Control.Continue.Class,+      module Control.Continue.Types,+      module Control.Continue.Utils,++      -- * Convenience reexports+      Alt(..),+      Plus(..)+    )+    where++import Control.Continue.Class+import Control.Continue.Types+import Control.Continue.Utils+import Data.Functor.Plus
+ Control/Continue/Class.hs view
@@ -0,0 +1,77 @@+-- |+-- Module:     Control.Continue.Class+-- Copyright:  (c) 2013 Ertugrul Soeylemez+-- License:    BSD3+-- Maintainer: Ertugrul Soeylemez <es@ertes.de>++{-# LANGUAGE UndecidableInstances #-}++module Control.Continue.Class+    ( -- * Suspension+      MonadContinue(..)+    )+    where++import qualified Control.Monad.Trans.State.Strict as Ss+import qualified Control.Monad.Trans.Writer.Strict as Ws+import Control.Monad.Trans.Identity+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Reader+import Control.Monad.Trans.State.Lazy+import Control.Monad.Trans.Writer.Lazy+import Data.Monoid+import Data.Functor.Plus+++-- | Type class for monads that support suspension and continuation+-- spots.++class (Plus f, Monad m, Monoid e) => MonadContinue e f m | m -> e, m -> f where+    -- | Add the given set of continuations and possibly suspend.+    addCont ::+        Either e a       -- ^ What to return now (left suspends).+        -> f (m a)  -- ^ What to run and return when reentering.+        -> m a++instance (MonadContinue e f m) => MonadContinue e f (IdentityT m) where+    addCont mx c = IdentityT $ addCont mx (fmap runIdentityT c)++instance (MonadContinue e f m) => MonadContinue e f (MaybeT m) where+    addCont mx c =+        MaybeT $+            addCont (fmap Just mx) (fmap runMaybeT c)++instance (MonadContinue e f m) => MonadContinue e f (ReaderT r m) where+    addCont mx c =+        ReaderT $ \env ->+            addCont mx (fmap (flip runReaderT env) c)++-- | Time travel warning: Captures the current state, not the state at+-- reentry!++instance (MonadContinue e f m) => MonadContinue e f (StateT s m) where+    addCont mx c =+        StateT $ \s ->+            addCont (fmap (flip (,) s) mx)+                    (fmap (flip runStateT s) c)++-- | Time travel warning: Captures the current state, not the state at+-- reentry!++instance (MonadContinue e f m) => MonadContinue e f (Ss.StateT s m) where+    addCont mx c =+        Ss.StateT $ \s ->+            addCont (fmap (flip (,) s) mx)+                    (fmap (flip Ss.runStateT s) c)++instance (MonadContinue e f m, Monoid l) => MonadContinue e f (WriterT l m) where+    addCont mx c =+        WriterT $+            addCont (fmap (flip (,) mempty) mx)+                    (fmap runWriterT c)++instance (MonadContinue e f m, Monoid l) => MonadContinue e f (Ws.WriterT l m) where+    addCont mx c =+        Ws.WriterT $+            addCont (fmap (flip (,) mempty) mx)+                    (fmap Ws.runWriterT c)
+ Control/Continue/Types.hs view
@@ -0,0 +1,174 @@+-- |+-- Module:     Control.Continue.Types+-- Copyright:  (c) 2012 Ertugrul Soeylemez+-- License:    BSD3+-- Maintainer: Ertugrul Soeylemez <es@ertes.de>+--+-- Types used in the continue library.++{-# LANGUAGE UndecidableInstances #-}++module Control.Continue.Types+    ( -- * Suspendable computations+      ContinueT(..),+      Continue,++      -- * Convenience types+      LastEx+    )+    where++import qualified Data.Bifunctor as Bi+import Control.Applicative+import Control.Arrow+import Control.Continue.Class+import Control.Exception (SomeException)+import Control.Monad+import Control.Monad.Base+import Control.Monad.Error.Class+import Control.Monad.Identity+import Control.Monad.Reader.Class+import Control.Monad.State.Class+import Control.Monad.Trans+import Control.Monad.Trans.Control+import Control.Monad.Writer.Class+import Data.Functor.Plus+import Data.Monoid+++-- | This monad transformer adds continuations under @f@ and @e@-typed+-- suspensions to @m@.++newtype ContinueT e f m a =+    ContinueT {+      runContinueT :: m (Either e a, f (ContinueT e f m a))+    }++instance (Monad m, Monoid e, Plus f) => Alternative (ContinueT e f m) where+    empty = ContinueT (return (Left mempty, zero))++    ContinueT c1 <|> ContinueT c2 =+        ContinueT $ do+            (mx1, cf1) <- c1+            (mx2, cf2) <- c2+            let mx = either (\ex1 -> Bi.first (ex1 <>) mx2) Right mx1+            return (mx, cf1 <!> cf2)++instance (Monad m, Plus f) => Applicative (ContinueT e f m) where+    pure x = ContinueT (return (Right x, zero))++    ContinueT cf <*> rx@(ContinueT cx) =+        ContinueT $ do+            (mf, cff) <- cf+            case mf of+              Left ex -> return (Left ex, fmap (<*> rx) cff)+              Right f -> do+                  (mx, cfx) <- cx+                  return (fmap f mx, fmap (fmap f) cfx)++instance (Functor f, Monad m) => Functor (ContinueT e f m) where+    fmap f (ContinueT c) = ContinueT (liftM (fmap f *** fmap (fmap f)) c)++instance (Monad m, Monoid e, Plus f) => Monad (ContinueT e f m) where+    return = pure++    ContinueT c >>= f =+        ContinueT $ do+            (mx, cfx') <- c+            let cfx = fmap (>>= f) cfx'+            case mx of+              Left ex -> return (Left ex, cfx)+              Right x -> do+                  (my, cfy) <- runContinueT (f x)+                  return (my, cfx <!> cfy)++    fail _ = ContinueT (return (Left mempty, zero))++instance (MonadBase b m, Monoid e, Plus f) => MonadBase b (ContinueT e f m) where+    liftBase = liftBaseDefault++instance (MonadBaseControl b m, Monoid e, Plus f) => MonadBaseControl b (ContinueT e f m) where+    data StM (ContinueT e f m) a =+        StContinueT (StM m (Either e a, f (ContinueT e f m a)))++    liftBaseWith k =+        ContinueT $ do+            x <-+                liftBaseWith $ \runB ->+                    k $ \(ContinueT c) ->+                        liftM StContinueT (runB c)+            return (Right x, zero)++    restoreM (StContinueT s) = ContinueT (restoreM s)++instance (Monad m, Monoid e, Plus f) => MonadContinue e f (ContinueT e f m) where+    addCont mx cf = ContinueT (return (mx, cf))++instance (Monad m, Monoid e, Plus f) => MonadError e (ContinueT e f m) where+    throwError ex = ContinueT (return (Left ex, zero))+    catchError (ContinueT c) h =+        ContinueT $ do+            (mx, cf) <- c+            case mx of+              Left ex -> do+                  (mxh, cfh) <- runContinueT (h ex)+                  return (mxh, cf <!> cfh)+              Right _ -> return (mx, cf)++-- | Warning:  If feedback is broken by suspension you get a run-time+-- error.++instance (MonadFix m, Monoid e, Plus f) => MonadFix (ContinueT e f m) where+    mfix f =+        ContinueT . mfix $ \ ~(mx, _) ->+            runContinueT . f .+            either (const $ error "Feedback broken by suspension") id $ mx++instance (MonadIO m, Monoid e, Plus f) => MonadIO (ContinueT e f m) where+    liftIO = ContinueT . liftM (\x -> (Right x, zero)) . liftIO++instance (Monad m, Monoid e, Plus f) => MonadPlus (ContinueT e f m) where+    mzero = empty+    mplus = (<|>)++instance (MonadReader r m, Monoid e, Plus f) => MonadReader r (ContinueT e f m) where+    ask = lift ask+    local f (ContinueT c) = ContinueT (local f c)+    reader = ContinueT . liftM (\x -> (Right x, zero)) . reader++instance (MonadState s m, Monoid e, Plus f) => MonadState s (ContinueT e f m) where+    get = lift get+    put = lift . put+    state = lift . state++instance (Plus f) => MonadTrans (ContinueT e f) where+    lift = ContinueT . liftM (\x -> (Right x, zero))++instance (MonadWriter l m, Monoid e, Plus f) => MonadWriter l (ContinueT e f m) where+    listen (ContinueT c) =+        ContinueT $ do+            ((mx, cf), w) <- listen c+            let addLog x = (x, w)+            return (fmap addLog mx, fmap (fmap addLog) cf)++    pass (ContinueT c) =+        ContinueT . pass $ do+            (mx, cf') <- c+            let cf = fmap (fmap fst) cf'+            case mx of+              Left ex      -> return ((Left ex, cf), id)+              Right (x, f) -> return ((Right x, cf), f)++    tell = lift . tell+    writer = lift . writer+++-- | 'ContinueT' over 'Identity'.++type Continue e f = ContinueT e f Identity+++-- | Type alias for the common case of using @'Last' 'SomeException'@ as+-- the suspension monoid.++type LastEx = Last SomeException
+ Control/Continue/Utils.hs view
@@ -0,0 +1,51 @@+-- |+-- Module:     Control.Continue.Utils+-- Copyright:  (c) 2012 Ertugrul Soeylemez+-- License:    BSD3+-- Maintainer: Ertugrul Soeylemez <es@ertes.de>+--+-- Suspension/continuation utilities.++module Control.Continue.Utils+    ( -- * Basic utilities+      addCont_,+      continue,+      continue_,+      suspend+    )+    where++import Control.Continue.Class+import Data.Functor.Plus+++-- | Add the given set of continuations without suspending.++addCont_ :: (MonadContinue e f m) => f (m ()) -> m ()+addCont_ = addCont (Right ())+++-- | Allow to continue here with the given value.++continue ::+    (MonadContinue e f m)+    => Either e a      -- ^ What to return now (left suspends).+    -> f (Either e a)  -- ^ What to return when reentering (left suspends).+    -> m a+continue mx = addCont mx . fmap (\mx -> addCont mx zero)+++-- | Allow to continue here.++continue_ ::+    (MonadContinue e f m)+    => f ()  -- ^ Reentering key.+    -> m ()+continue_ = addCont (Right ()) . fmap (const $ return ())+++-- | Suspend with the given value.  Does not register any continuation+-- spots.  Note that @suspend mempty@ is equivalent to @empty@.++suspend :: (MonadContinue e f m) => e -> m a+suspend ex = addCont (Left ex) zero
+ LICENSE view
@@ -0,0 +1,32 @@+continue license+Copyright (c) 2012, Ertugrul Soeylemez++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 the author nor the names of any 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.
+ README.md view
@@ -0,0 +1,95 @@+The ContinueT monad transformer+===============================++Quickstart tutorial+-------------------++This monad transformer allows you to set continuation spots in a+computation and reenter it at any of those spots possibly causing+different behavior:++    label name = continue_ (M.singleton name ())++    myComp = do+        label "first"+        liftIO (putStrLn "Hello")+        label "second"+        liftIO (putStrLn "World!")++This computation gives you two spots for reentry, "first" and "second".+If you reenter at "first", the whole computation will be run again.  If+you reenter at "second", only the second `putStrLn` computation will be+run again.+++### Advanced reentering++The most general way to reenter is to perform a computation when+reentering:++    addCont (Right False) . M.singleton "abc" $ do+        liftIO (putStrLn "Reentered at spot abc.")+        return True++In the primary run this computation will just return `False`, but it+will also register a continuation spot.  When you reenter the+computation using that spot, it will return `True` instead.+++### Suspension++A `ContinueT` monad also allows you to suspend a computation.  This+basically means that the computation is aborted at some spot to be+reentered somewhere else (or at the same spot) later.  You can do this+with the `empty` combinator as well as the `suspend` function.  Examples+TODO.+++ContinueT explained+-------------------++`ContinueT` takes four arguments:++    newtype ContinueT e f m a++To form a monad, *e* has to be a monoid, *f* has to be a `Plus` functor+(as defined by the [semigroupoids] package) and *m* has to be a monad.+++### The reentry functor++The most important parameter is the reentry functor *f*.  It represents+the type for maps of reentry points.  Example:++    ContinueT e (Map String) m a++A computation of this type may register reentry points indexed by+strings.  All registered reentry points are combined according to the+functor's `Plus` instance.+++### The suspension monoid++Computations may suspend, in which case control is returned to a+controller, which may be the application loop or the `(<|>)` combinator:++    c1 <|> c2++This computation runs both `c1` and `c2` (note: even if neither+suspends) and returns the result of the left-most computation that did+not suspend.++When a computation suspends it may do so with a value of type *e* that+might communicate the reason for suspending.  This type must be a+monoid, because multiple branches of a `(<|>)` composition may suspend,+in which case the suspension values are combined according to the+`Monoid` instance of *e*.++A reasonable suspension monoid is `Last SomeException`, and since this+will likely be a very common choice this library defines a shorthand for+it:++    type LastEx = Last SomeException+++[semigroupoids]: <http://hackage.haskell.org/package/semigroupoids>
+ Setup.lhs view
@@ -0,0 +1,12 @@+continue setup script+Copyright (C) 2012, Ertugrul Soeylemez++Please see the LICENSE file for terms and conditions of use,+modification and distribution of this package, including this file.++> module Main where+>+> import Distribution.Simple+>+> main :: IO ()+> main = defaultMain
+ continue.cabal view
@@ -0,0 +1,62 @@+Name:          continue+Version:       0.1.0+Category:      Continuation-based user interaction monad+Synopsis:      Control+Maintainer:    Ertugrul Söylemez <es@ertes.de>+Author:        Ertugrul Söylemez <es@ertes.de>+Copyright:     (c) 2012 Ertugrul Söylemez+License:       BSD3+License-file:  LICENSE+Build-type:    Simple+Stability:     experimental+Cabal-version: >= 1.10+Extra-source-files: README.md+Description:+    This library implements a monad transformer for suspendable+    computations, similar and related to free comonads.  It allows to+    write continuation-based web frameworks, command line applications+    and similar interfaces.++Source-repository head+    type:     git+    location: git://github.com/ertes/continue.git++Library+    Build-depends:+        base              >= 4.5 && < 5,+        bifunctors        >= 3.0 && < 4,+        monad-control     >= 0.3 && < 1,+        mtl               >= 2.0 && < 3,+        semigroupoids     >= 3.0 && < 4,+        transformers      >= 0.3 && < 1,+        transformers-base >= 0.4 && < 1+    Default-language: Haskell2010+    Default-extensions:+        FlexibleInstances+        FunctionalDependencies+        MultiParamTypeClasses+        TypeFamilies+    Other-extensions:+        UndecidableInstances+    GHC-Options: -W+    Exposed-modules:+        Control.Continue+        Control.Continue.Class+        Control.Continue.Types+        Control.Continue.Utils++-- Test-suite continue-test+--     Type: exitcode-stdio-1.0+--     Build-depends:+--         base >= 4.5 && < 5,+--         conduit,+--         containers,+--         continue,+--         http-types,+--         wai,+--         warp+--     Default-language: Haskell2010+--     Default-extensions:+--     GHC-Options: -threaded -rtsopts+--     Hs-source-dirs: test+--     Main-is: Main.hs