continue 0.1.1 → 0.2.0
raw patch · 7 files changed
+447/−334 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Continue: (<!>) :: Alt f => f a -> f a -> f a
- Control.Continue: class Functor f => Alt (f :: * -> *)
- Control.Continue: class Alt f => Plus (f :: * -> *)
- Control.Continue: many :: (Alt f, Applicative f) => f a -> f [a]
- Control.Continue: some :: (Alt f, Applicative f) => f a -> f [a]
- Control.Continue: zero :: Plus f => f a
- Control.Continue.Class: addCont :: MonadContinue e f m => Either e a -> f (m a) -> m a
- Control.Continue.Class: class (Plus f, Monad m, Monoid e) => MonadContinue e f m | m -> e, m -> f
- Control.Continue.Class: instance (MonadContinue e f m, Monoid l) => MonadContinue e f (WriterT l m)
- Control.Continue.Class: instance MonadContinue e f m => MonadContinue e f (IdentityT m)
- Control.Continue.Class: instance MonadContinue e f m => MonadContinue e f (MaybeT m)
- Control.Continue.Class: instance MonadContinue e f m => MonadContinue e f (ReaderT r m)
- Control.Continue.Class: instance MonadContinue e f m => MonadContinue e f (StateT s m)
- Control.Continue.Types: ContinueT :: m (Either e a, f (ContinueT e f m a)) -> ContinueT e f m a
- Control.Continue.Types: instance (Functor f, Monad m) => Functor (ContinueT e f m)
- Control.Continue.Types: instance (Monad m, Monoid e, Plus f) => Alternative (ContinueT e f m)
- Control.Continue.Types: instance (Monad m, Monoid e, Plus f) => Monad (ContinueT e f m)
- Control.Continue.Types: instance (Monad m, Monoid e, Plus f) => MonadContinue e f (ContinueT e f m)
- Control.Continue.Types: instance (Monad m, Monoid e, Plus f) => MonadError e (ContinueT e f m)
- Control.Continue.Types: instance (Monad m, Monoid e, Plus f) => MonadPlus (ContinueT e f m)
- Control.Continue.Types: instance (Monad m, Plus f) => Applicative (ContinueT e f m)
- Control.Continue.Types: instance (MonadBase b m, Monoid e, Plus f) => MonadBase b (ContinueT e f m)
- Control.Continue.Types: instance (MonadBaseControl b m, Monoid e, Plus f) => MonadBaseControl b (ContinueT e f m)
- Control.Continue.Types: instance (MonadFix m, Monoid e, Plus f) => MonadFix (ContinueT e f m)
- Control.Continue.Types: instance (MonadIO m, Monoid e, Plus f) => MonadIO (ContinueT e f m)
- Control.Continue.Types: instance (MonadReader r m, Monoid e, Plus f) => MonadReader r (ContinueT e f m)
- Control.Continue.Types: instance (MonadState s m, Monoid e, Plus f) => MonadState s (ContinueT e f m)
- Control.Continue.Types: instance (MonadWriter l m, Monoid e, Plus f) => MonadWriter l (ContinueT e f m)
- Control.Continue.Types: instance Plus f => MonadTrans (ContinueT e f)
- Control.Continue.Types: newtype ContinueT e f m a
- Control.Continue.Types: runContinueT :: ContinueT e f m a -> m (Either e a, f (ContinueT e f m a))
- Control.Continue.Types: type Continue e f = ContinueT e f Identity
- Control.Continue.Types: type LastEx = Last SomeException
- Control.Continue.Utils: addCont_ :: MonadContinue e f m => f (m ()) -> m ()
- Control.Continue.Utils: continue :: MonadContinue e f m => Either e a -> f (Either e a) -> m a
- Control.Continue.Utils: continue_ :: MonadContinue e f m => f () -> m ()
- Control.Continue.Utils: suspend :: MonadContinue e f m => e -> m a
+ Control.Monad.Continue: (<!>) :: Alt f => f a -> f a -> f a
+ Control.Monad.Continue: ContinueT :: m (Either e a, f (ContinueT e f m a)) -> ContinueT e f m a
+ Control.Monad.Continue: class Functor f => Alt (f :: * -> *)
+ Control.Monad.Continue: class Alt f => Plus (f :: * -> *)
+ Control.Monad.Continue: instance (Functor f, Monad m) => Functor (ContinueT e f m)
+ Control.Monad.Continue: instance (Monad m, Monoid e, Plus f) => Alternative (ContinueT e f m)
+ Control.Monad.Continue: instance (Monad m, Monoid e, Plus f) => Monad (ContinueT e f m)
+ Control.Monad.Continue: instance (Monad m, Monoid e, Plus f) => MonadContinue e f (ContinueT e f m)
+ Control.Monad.Continue: instance (Monad m, Monoid e, Plus f) => MonadError e (ContinueT e f m)
+ Control.Monad.Continue: instance (Monad m, Monoid e, Plus f) => MonadPlus (ContinueT e f m)
+ Control.Monad.Continue: instance (Monad m, Plus f) => Applicative (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadBase b m, Monoid e, Plus f) => MonadBase b (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadBaseControl b m, Monoid e, Plus f) => MonadBaseControl b (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadFix m, Monoid e, Plus f) => MonadFix (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadIO m, Monoid e, Plus f) => MonadIO (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadReader r m, Monoid e, Plus f) => MonadReader r (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadState s m, Monoid e, Plus f) => MonadState s (ContinueT e f m)
+ Control.Monad.Continue: instance (MonadWriter l m, Monoid e, Plus f) => MonadWriter l (ContinueT e f m)
+ Control.Monad.Continue: instance Plus f => MonadTrans (ContinueT e f)
+ Control.Monad.Continue: many :: (Alt f, Applicative f) => f a -> f [a]
+ Control.Monad.Continue: mapContinueT :: (Functor f, Monad n) => (forall a. m a -> n a) -> ContinueT e f m a -> ContinueT e f n a
+ Control.Monad.Continue: newtype ContinueT e f m a
+ Control.Monad.Continue: orElse :: (Alt f, Monad m, Monoid e) => ContinueT e f m a -> ContinueT e f m a -> ContinueT e f m a
+ Control.Monad.Continue: runContinue :: Continue e f a -> (Either e a, f (Continue e f a))
+ Control.Monad.Continue: runContinueT :: ContinueT e f m a -> m (Either e a, f (ContinueT e f m a))
+ Control.Monad.Continue: some :: (Alt f, Applicative f) => f a -> f [a]
+ Control.Monad.Continue: type Continue e f = ContinueT e f Identity
+ Control.Monad.Continue: type LastEx = Last SomeException
+ Control.Monad.Continue: zero :: Plus f => f a
+ Control.Monad.Continue.Class: addCont :: MonadContinue e f m => Either e a -> f (m a) -> m a
+ Control.Monad.Continue.Class: addCont_ :: MonadContinue e f m => f (m ()) -> m ()
+ Control.Monad.Continue.Class: class (Plus f, Monad m, Monoid e) => MonadContinue e f m | m -> e, m -> f
+ Control.Monad.Continue.Class: continue :: MonadContinue e f m => Either e a -> f (Either e a) -> m a
+ Control.Monad.Continue.Class: continue_ :: MonadContinue e f m => f () -> m ()
+ Control.Monad.Continue.Class: instance (MonadContinue e f m, Monoid l) => MonadContinue e f (WriterT l m)
+ Control.Monad.Continue.Class: instance MonadContinue e f m => MonadContinue e f (IdentityT m)
+ Control.Monad.Continue.Class: instance MonadContinue e f m => MonadContinue e f (MaybeT m)
+ Control.Monad.Continue.Class: instance MonadContinue e f m => MonadContinue e f (ReaderT r m)
+ Control.Monad.Continue.Class: instance MonadContinue e f m => MonadContinue e f (StateT s m)
+ Control.Monad.Continue.Class: suspend :: MonadContinue e f m => e -> m a
+ Control.Monad.Continue.Class: suspendWith :: MonadContinue e f m => f (m a) -> m a
Files
- Control/Continue.hs +0/−24
- Control/Continue/Class.hs +0/−77
- Control/Continue/Types.hs +0/−174
- Control/Continue/Utils.hs +0/−51
- Control/Monad/Continue.hs +305/−0
- Control/Monad/Continue/Class.hs +123/−0
- continue.cabal +19/−8
− Control/Continue.hs
@@ -1,24 +0,0 @@--- |--- 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
@@ -1,77 +0,0 @@--- |--- 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
@@ -1,174 +0,0 @@--- |--- 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
@@ -1,51 +0,0 @@--- |--- 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
+ Control/Monad/Continue.hs view
@@ -0,0 +1,305 @@+-- |+-- Module: Control.Monad.Continue+-- Copyright: (c) 2012 Ertugrul Soeylemez+-- License: BSD3+-- Maintainer: Ertugrul Soeylemez <es@ertes.de>+--+-- 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, where you want to reenter a computation at+-- arbitrary spots.++{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.Continue+ ( -- $doc++ -- * Continue+ Continue,+ runContinue,++ -- * ContinueT+ ContinueT(..),+ mapContinueT,++ -- * Combinators+ orElse,++ -- * Convenience types+ LastEx,++ -- * Reexports+ module Control.Monad.Continue.Class,+ Alt(..),+ Plus(..)+ )+ where++import qualified Data.Bifunctor as Bi+import Control.Applicative+import Control.Arrow+import Control.Exception (SomeException)+import Control.Monad+import Control.Monad.Base+import Control.Monad.Continue.Class+import Control.Monad.Error.Class+import Control.Monad.Fix+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+++-- | Apply the given morphism to the underlying monad.++mapContinueT ::+ (Functor f, Monad n)+ => (forall a. m a -> n a) -- ^ Monad morphism to apply.+ -> ContinueT e f m a+ -> ContinueT e f n a+mapContinueT mm (ContinueT c) =+ ContinueT $ do+ (mx, cf) <- mm c+ return (mx, fmap (mapContinueT mm) cf)+++-- | Similar to '<|>', but tries the second computation only if the+-- first one actually suspends. Note that not running the second+-- computation also means that it can't register reentry spots.+--+-- As an operator this function is infixr 3.++orElse ::+ (Alt f, Monad m, Monoid e)+ => ContinueT e f m a+ -> ContinueT e f m a+ -> ContinueT e f m a+orElse (ContinueT c1) (ContinueT c2) =+ ContinueT $ do+ (mx1, cf1) <- c1+ case mx1 of+ Left ex1 -> do+ (mx2, cf2) <- c2+ return (Bi.first (ex1 <>) mx2, cf1 <!> cf2)+ Right _ -> return (mx1, cf1)++infixr 3 `orElse`+++-- | Run the given 'Continue' computation.++runContinue :: Continue e f a -> (Either e a, f (Continue e f a))+runContinue = runIdentity . runContinueT+++{- $doc++A computation of type @'ContinueT' e f m a@ is a computation that may+either conclude with a value of type @a@ or suspend with a value of type+@e@. Before suspending or concluding it may register a set of reentry+spots of type @f (ContinueT e f m a)@. These spots are collected and+returned along with the suspension/conclusion value:++> newtype ContinueT e f m a++To run a @ContinueT@ computation you can use the 'runContinueT'+function:++> runContinueT :: ContinueT e f m a+> -> m (Either e a, f (ContinueT e f m a))++The result is either a suspension value of type @e@ or a conclusion of+type @a@. In both cases you can reenter the computation at the+registered spots. Example:++> type MyMonad = ContinueT () (Map String) Identity+>+> myComp :: MyMonad Integer+> myComp = do+> x <- continue (Right 3) (M.singleton "x" (Right 15))+> y <- continue (Right 4) (M.singleton "y" (Right 17))+> return (x + y)++When you first run this computation the result will be the conclusion 3++ 4. Since 'MyMonad' transforms to 'Identity' we can use the+convenience type alias 'Continue' and the function 'runContinue':++> type MyMonad = Continue () (Map String)+>+> runContinue myComp+> = (Right 7, reentryMap)++Along with the result you will also get a reentry map of type @Map+String (MyMonad Integer)@. If you run the computation indexed by \"x\",+you will get the result 15 + 4. This iteration itself will return a new+reentry map on its part. That map will contain only the reentry spot+\"y\", because the reentry indexed by \"x\" does not register itself+again.++You can use the more general 'addCont' function to register arbitrary+reentry spots, which themselves are allowed to register new spots. Also+In some kinds of applications you would want to combine the reentry maps+produced. You can use the '<!>' function to do that:++> let overallReentryMap = reentryMap1 <!> reentryMap2++Since @e@ is required to be a monoid, @ContinueT@ forms a family of+alternative functors that implement choice based on suspension and+conclusion. The computation 'empty' always suspends with 'mempty'.++> x <|> y++This computation concludes with the conclusion of either @x@ or @y@+trying them in that order, or suspends if both of them suspend. Note+that both computations are performed to their conclusion or suspension.+This allows @y@ both to have monadic effects as well as to register+reentry points, even if @x@ concludes.++There is also a combinator 'orElse' that tries @y@ only if @x@ actually+suspends. In that case, if @x@ concludes, then @y@ cannot register+reentry spots or have effects in the underlying monad.++-}
+ Control/Monad/Continue/Class.hs view
@@ -0,0 +1,123 @@+-- |+-- Module: Control.Monad.Continue.Class+-- Copyright: (c) 2013 Ertugrul Soeylemez+-- License: BSD3+-- Maintainer: Ertugrul Soeylemez <es@ertes.de>++{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.Continue.Class+ ( -- * Suspension+ MonadContinue(..),++ -- * Basic utilities+ addCont_,+ continue,+ continue_,+ suspend,+ suspendWith+ )+ 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.Functor.Plus+import Data.Monoid+++-- | 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. Use 'ContinueT' over 'StateT' instead to fix this.++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. Use 'ContinueT' over 'StateT' instead to fix this.++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)+++-- | 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+++-- | Suspend with 'mempty' and register the given continuations. Note+-- that @suspendWith zero@ is equivalent to @empty@.++suspendWith :: (MonadContinue e f m) => f (m a) -> m a+suspendWith = addCont (Left mempty)
continue.cabal view
@@ -1,7 +1,7 @@ Name: continue-Version: 0.1.1+Version: 0.2.0 Category: Control-Synopsis: Continuation-based user interaction monad+Synopsis: Monads with suspension and arbitrary-spot reentry Maintainer: Ertugrul Söylemez <es@ertes.de> Author: Ertugrul Söylemez <es@ertes.de> Copyright: (c) 2012 Ertugrul Söylemez@@ -15,7 +15,8 @@ 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.+ and similar interfaces, where you want to reenter a computation at+ arbitrary spots. Source-repository head type: git@@ -34,29 +35,39 @@ Default-extensions: FlexibleInstances FunctionalDependencies+ RankNTypes MultiParamTypeClasses TypeFamilies Other-extensions: UndecidableInstances GHC-Options: -W Exposed-modules:- Control.Continue- Control.Continue.Class- Control.Continue.Types- Control.Continue.Utils+ Control.Monad.Continue+ Control.Monad.Continue.Class -- Test-suite continue-test -- Type: exitcode-stdio-1.0 -- Build-depends: -- base >= 4.5 && < 5,+-- blaze-builder,+-- boomerang, -- conduit, -- containers, -- continue, -- http-types,+-- mtl, -- wai,--- warp+-- warp,+-- web-routes,+-- web-routes-boomerang -- Default-language: Haskell2010 -- Default-extensions:+-- FlexibleInstances+-- MultiParamTypeClasses+-- OverloadedStrings+-- TemplateHaskell+-- TypeOperators+-- UndecidableInstances -- GHC-Options: -threaded -rtsopts -- Hs-source-dirs: test -- Main-is: Main.hs