CC-delcont-cxe 0.1.0.0 → 0.1.0.1
raw patch · 3 files changed
+252/−252 lines, 3 files
Files
- CC-delcont-cxe.cabal +2/−2
- Control/Monad/CC/CCCxe.hs +250/−0
- Control/Monad/CC/CCcxe.hs +0/−250
CC-delcont-cxe.cabal view
@@ -1,5 +1,5 @@ name: CC-delcont-cxe -version: 0.1.0.0 +version: 0.1.0.1 author: Oleg Kiselyov maintainer: shelarcy <shelarcy@gmail.com> license: BSD3 @@ -40,7 +40,7 @@ library build-depends: base >= 3 && < 5, mtl exposed-modules: - Control.Monad.CC.CCcxe + Control.Monad.CC.CCCxe other-modules: cc-options: ld-options:
+ Control/Monad/CC/CCCxe.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE PatternGuards, KindSignatures #-}+{-# LANGUAGE ExistentialQuantification, RankNTypes, ImpredicativeTypes #-}++-- | This file is the CPS version of <http://hackage.haskell.org/package/CC-delcont-exc>'s Control.Monad.CC.CCExc, implementing the identical+-- interface+--+-- Monad transformer for multi-prompt delimited control+-- It implements the superset of the interface described in+--+-- * \"/A Monadic Framework for Delimited Continuations/\",+-- R. Kent Dybvig, Simon Peyton Jones, and Amr Sabry+-- JFP, v17, N6, pp. 687--730, 2007.+-- <http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR615>+--+-- The first main difference is the use of generalized prompts, which+-- do not have to be created with new_prompt and therefore can be defined+-- at top level. That removes one of the main practical drawbacks of+-- Dybvig et al implementations: the necessity to carry around the prompts+-- throughout all the code.+--+-- The delimited continuation monad is parameterized by the flavor+-- of generalized prompts. The end of this code defines several flavors;+-- the library users may define their own. User-defined flavors are +-- especially useful when user's code uses a small closed set of answer-types. +-- Flavors PP and PD below are more general, assuming the set of possible+-- answer-types is open and Typeable. If the user wishes to create several+-- distinct prompts with the same answer-types, the user should use+-- the flavor of prompts accepting an integral prompt identifier, such as PD.+-- Prompts of the flavor PD correspond to the prompts in Dybvig, Peyton Jones,+-- Sabry framework. If the user wishes to generate unique prompts, the user+-- should arrange himself for the generation of unique integers+-- (using a state monad, for example). On the other hand, the user+-- can differentiate answer-types using `newtype.' The latter can+-- only produce the set of distinct prompts that is fixed at run-time.+-- Sometimes that is sufficient. There is not need to create a gensym+-- monad then.+--+-- See Control.Monad.CC.CCExc for further comments about the implementation++module Control.Monad.CC.CCCxe (+ -- * Types+ CC,+ SubCont,+ CCT,+ Prompt,++ -- * Basic delimited control operations+ pushPrompt,+ takeSubCont,+ pushSubCont,+ runCC,++ -- * Useful derived operations+ abortP,+ shiftP,+ shift0P,+ controlP,++ -- * Pre-defined prompt flavors+ PS, ps,+ P2, p2L, p2R,+ PP, pp,+ PM, pm,+ PD, newPrompt,+ as_prompt_type+ ) where++import Control.Monad.Trans+import Data.Typeable -- for prompts of the flavor PP, PD++-- | Delimited-continuation monad transformer+-- It is parameterized by the prompt flavor p+-- The first argument is the regular (success) continuation,+-- the second argument is the bubble, or a resumable exception+newtype CC p m a = + CC{unCC:: forall w. (a -> m w) -> + (forall x. SubCont p m x a -> p m x -> m w) -> + m w}++-- | The captured sub-continuation+type SubCont p m a b = CC p m a -> CC p m b++-- | The type of control operator's body+type CCT p m a w = SubCont p m a w -> CC p m w++-- | Generalized prompts for the answer-type w: an injection-projection pair+type Prompt p m w = + (forall x. CCT p m x w -> p m x,+ forall x. p m x -> Maybe (CCT p m x w))+++-- --------------------------------------------------------------------+-- | CC monad: general monadic operations++instance Monad m => Monad (CC p m) where+ return x = CC $ \ki kd -> ki x++ m >>= f = CC $ \ki kd -> unCC m + (\a -> unCC (f a) ki kd)+ (\ctx -> kd (\x -> ctx x >>= f))++instance MonadTrans (CC p) where+ lift m = CC $ \ki kd -> m >>= ki++instance MonadIO m => MonadIO (CC p m) where+ liftIO = lift . liftIO++-- --------------------------------------------------------------------+-- Basic Operations of the delimited control interface++pushPrompt :: Monad m =>+ Prompt p m w -> CC p m w -> CC p m w+pushPrompt p@(_,proj) body = CC $ \ki kd -> + let kd' ctx body | Just b <- proj body = unCC (b ctx) ki kd+ kd' ctx body = kd (\x -> pushPrompt p (ctx x)) body+ in unCC body ki kd'+++-- | Create the initial bubble+takeSubCont :: Monad m =>+ Prompt p m w -> CCT p m x w -> CC p m x+takeSubCont p@(inj,_) body = CC $ \ki kd -> kd id (inj body)++-- | Apply the captured continuation+pushSubCont :: Monad m => SubCont p m a b -> CC p m a -> CC p m b+pushSubCont = ($)++runCC :: Monad m => CC (p :: (* -> *) -> * -> *) m a -> m a+runCC m = unCC m return err+ where+ err = error "Escaping bubble: you have forgotten pushPrompt"+++-- --------------------------------------------------------------------+-- Useful derived operations++abortP :: Monad m => + Prompt p m w -> CC p m w -> CC p m any+abortP p e = takeSubCont p (\_ -> e)++shiftP :: Monad m => + Prompt p m w -> ((a -> CC p m w) -> CC p m w) -> CC p m a+shiftP p f = takeSubCont p $ \sk -> + pushPrompt p (f (\c -> + pushPrompt p (pushSubCont sk (return c))))++shift0P :: Monad m => + Prompt p m w -> ((a -> CC p m w) -> CC p m w) -> CC p m a+shift0P p f = takeSubCont p $ \sk -> + f (\c -> + pushPrompt p (pushSubCont sk (return c)))++controlP :: Monad m => + Prompt p m w -> ((a -> CC p m w) -> CC p m w) -> CC p m a+controlP p f = takeSubCont p $ \sk -> + pushPrompt p (f (\c -> + pushSubCont sk (return c)))++-- --------------------------------------------------------------------+-- Prompt flavors++-- | The extreme case: prompts for the single answer-type w.+-- The monad (CC PS) then is the monad for regular (single-prompt) +-- delimited continuations+newtype PS w m x = PS (CCT (PS w) m x w)++-- There is only one generalized prompt of the flavor PS for a+-- given answer-type w. It is defined below+ps :: Prompt (PS w) m w+ps = (inj, prj)+ where+ inj = PS+ prj (PS x) = Just x++-- | Prompts for the closed set of answer-types+-- The following prompt flavor P2, for two answer-types w1 and w2,+-- is given as an example. Typically, a programmer would define their+-- own variant data type with variants for the answer-types that occur+-- in their program.++newtype P2 w1 w2 m x = + P2 (Either (CCT (P2 w1 w2) m x w1) (CCT (P2 w1 w2) m x w2))+++-- | There are two generalized prompts of the flavor P2"+p2L :: Prompt (P2 w1 w2) m w1+p2L = (inj, prj)+ where+ inj = P2 . Left+ prj (P2 (Left x)) = Just x+ prj _ = Nothing++p2R :: Prompt (P2 w1 w2) m w2+p2R = (inj, prj)+ where+ inj = P2 . Right+ prj (P2 (Right x)) = Just x+ prj _ = Nothing+++-- | Prompts for the open set of answer-types++data PP m x = forall w. Typeable w => PP (CCT PP m x w)++-- | We need to wrap the type alias CCT into a newtype. Otherwise, gcast+-- doesn't work. We can't treat (CCT p m a w) as a an application of+-- the `type constructor' (CCT p m a) to the type w: type aliases can't +-- be partially applied. But we can treat the type (NCCT p m a w) that way.+newtype NCCT p m a w = NCCT{unNCCT :: CCT p m a w}++pp :: Typeable w => Prompt PP m w+pp = (inj, prj)+ where+ inj = PP+ prj (PP c) = maybe Nothing (Just . unNCCT) (gcast (NCCT c))++-- | The same as PP but with the phantom parameter c+-- The parameter is useful to statically enforce various constrains+-- (statically pass some information between shift and reset)+-- The prompt PP is too `dynamic': all errors are detected dynamically+-- See Generator2.hs for an example+data PM c m x = forall w. Typeable w => PM (CCT (PM c) m x w)++pm :: Typeable w => Prompt (PM c) m w+pm = (inj, prj)+ where+ inj = PM+ prj (PM c) = maybe Nothing (Just . unNCCT) (gcast (NCCT c))++-- | Open set of answer types, with an additional distinction (given by+-- integer identifiers)+-- This prompt flavor corresponds to the prompts in the Dybvig, Peyton-Jones,+-- Sabry framework (modulo the Typeable constraint).++data PD m x = forall w. Typeable w => PD Int (CCT PD m x w)++newPrompt :: Typeable w => Int -> Prompt PD m w+newPrompt mark = (inj, prj)+ where+ inj = PD mark+ prj (PD mark' c) | mark' == mark, + Just (NCCT x) <- gcast (NCCT c) = Just x+ prj _ = Nothing++-- | It is often helpful, for clarity of error messages, to specify the +-- answer-type associated with the prompt explicitly (rather than relying +-- on the type inference to figure that out). The following function+-- is useful for that purpose.+as_prompt_type :: Prompt p m w -> w -> Prompt p m w+as_prompt_type = const
− Control/Monad/CC/CCcxe.hs
@@ -1,250 +0,0 @@-{-# LANGUAGE PatternGuards, KindSignatures #-}-{-# LANGUAGE ExistentialQuantification, RankNTypes, ImpredicativeTypes #-}---- | This file is the CPS version of <http://hackage.haskell.org/package/CC-delcont-exc>'s Control.Monad.CC.CCExc, implementing the identical--- interface------ Monad transformer for multi-prompt delimited control--- It implements the superset of the interface described in------ * \"/A Monadic Framework for Delimited Continuations/\",--- R. Kent Dybvig, Simon Peyton Jones, and Amr Sabry--- JFP, v17, N6, pp. 687--730, 2007.--- <http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR615>------ The first main difference is the use of generalized prompts, which--- do not have to be created with new_prompt and therefore can be defined--- at top level. That removes one of the main practical drawbacks of--- Dybvig et al implementations: the necessity to carry around the prompts--- throughout all the code.------ The delimited continuation monad is parameterized by the flavor--- of generalized prompts. The end of this code defines several flavors;--- the library users may define their own. User-defined flavors are --- especially useful when user's code uses a small closed set of answer-types. --- Flavors PP and PD below are more general, assuming the set of possible--- answer-types is open and Typeable. If the user wishes to create several--- distinct prompts with the same answer-types, the user should use--- the flavor of prompts accepting an integral prompt identifier, such as PD.--- Prompts of the flavor PD correspond to the prompts in Dybvig, Peyton Jones,--- Sabry framework. If the user wishes to generate unique prompts, the user--- should arrange himself for the generation of unique integers--- (using a state monad, for example). On the other hand, the user--- can differentiate answer-types using `newtype.' The latter can--- only produce the set of distinct prompts that is fixed at run-time.--- Sometimes that is sufficient. There is not need to create a gensym--- monad then.------ See Control.Monad.CC.CCExc for further comments about the implementation--module Control.Monad.CC.CCCxe (- -- * Types- CC,- SubCont,- CCT,- Prompt,-- -- * Basic delimited control operations- pushPrompt,- takeSubCont,- pushSubCont,- runCC,-- -- * Useful derived operations- abortP,- shiftP,- shift0P,- controlP,-- -- * Pre-defined prompt flavors- PS, ps,- P2, p2L, p2R,- PP, pp,- PM, pm,- PD, newPrompt,- as_prompt_type- ) where--import Control.Monad.Trans-import Data.Typeable -- for prompts of the flavor PP, PD---- | Delimited-continuation monad transformer--- It is parameterized by the prompt flavor p--- The first argument is the regular (success) continuation,--- the second argument is the bubble, or a resumable exception-newtype CC p m a = - CC{unCC:: forall w. (a -> m w) -> - (forall x. SubCont p m x a -> p m x -> m w) -> - m w}---- | The captured sub-continuation-type SubCont p m a b = CC p m a -> CC p m b---- | The type of control operator's body-type CCT p m a w = SubCont p m a w -> CC p m w---- | Generalized prompts for the answer-type w: an injection-projection pair-type Prompt p m w = - (forall x. CCT p m x w -> p m x,- forall x. p m x -> Maybe (CCT p m x w))----- ----------------------------------------------------------------------- | CC monad: general monadic operations--instance Monad m => Monad (CC p m) where- return x = CC $ \ki kd -> ki x-- m >>= f = CC $ \ki kd -> unCC m - (\a -> unCC (f a) ki kd)- (\ctx -> kd (\x -> ctx x >>= f))--instance MonadTrans (CC p) where- lift m = CC $ \ki kd -> m >>= ki--instance MonadIO m => MonadIO (CC p m) where- liftIO = lift . liftIO---- ----------------------------------------------------------------------- Basic Operations of the delimited control interface--pushPrompt :: Monad m =>- Prompt p m w -> CC p m w -> CC p m w-pushPrompt p@(_,proj) body = CC $ \ki kd -> - let kd' ctx body | Just b <- proj body = unCC (b ctx) ki kd- kd' ctx body = kd (\x -> pushPrompt p (ctx x)) body- in unCC body ki kd'----- | Create the initial bubble-takeSubCont :: Monad m =>- Prompt p m w -> CCT p m x w -> CC p m x-takeSubCont p@(inj,_) body = CC $ \ki kd -> kd id (inj body)---- | Apply the captured continuation-pushSubCont :: Monad m => SubCont p m a b -> CC p m a -> CC p m b-pushSubCont = ($)--runCC :: Monad m => CC (p :: (* -> *) -> * -> *) m a -> m a-runCC m = unCC m return err- where- err = error "Escaping bubble: you have forgotten pushPrompt"----- ----------------------------------------------------------------------- Useful derived operations--abortP :: Monad m => - Prompt p m w -> CC p m w -> CC p m any-abortP p e = takeSubCont p (\_ -> e)--shiftP :: Monad m => - Prompt p m w -> ((a -> CC p m w) -> CC p m w) -> CC p m a-shiftP p f = takeSubCont p $ \sk -> - pushPrompt p (f (\c -> - pushPrompt p (pushSubCont sk (return c))))--shift0P :: Monad m => - Prompt p m w -> ((a -> CC p m w) -> CC p m w) -> CC p m a-shift0P p f = takeSubCont p $ \sk -> - f (\c -> - pushPrompt p (pushSubCont sk (return c)))--controlP :: Monad m => - Prompt p m w -> ((a -> CC p m w) -> CC p m w) -> CC p m a-controlP p f = takeSubCont p $ \sk -> - pushPrompt p (f (\c -> - pushSubCont sk (return c)))---- ----------------------------------------------------------------------- Prompt flavors---- | The extreme case: prompts for the single answer-type w.--- The monad (CC PS) then is the monad for regular (single-prompt) --- delimited continuations-newtype PS w m x = PS (CCT (PS w) m x w)---- There is only one generalized prompt of the flavor PS for a--- given answer-type w. It is defined below-ps :: Prompt (PS w) m w-ps = (inj, prj)- where- inj = PS- prj (PS x) = Just x---- | Prompts for the closed set of answer-types--- The following prompt flavor P2, for two answer-types w1 and w2,--- is given as an example. Typically, a programmer would define their--- own variant data type with variants for the answer-types that occur--- in their program.--newtype P2 w1 w2 m x = - P2 (Either (CCT (P2 w1 w2) m x w1) (CCT (P2 w1 w2) m x w2))----- | There are two generalized prompts of the flavor P2"-p2L :: Prompt (P2 w1 w2) m w1-p2L = (inj, prj)- where- inj = P2 . Left- prj (P2 (Left x)) = Just x- prj _ = Nothing--p2R :: Prompt (P2 w1 w2) m w2-p2R = (inj, prj)- where- inj = P2 . Right- prj (P2 (Right x)) = Just x- prj _ = Nothing----- | Prompts for the open set of answer-types--data PP m x = forall w. Typeable w => PP (CCT PP m x w)---- | We need to wrap the type alias CCT into a newtype. Otherwise, gcast--- doesn't work. We can't treat (CCT p m a w) as a an application of--- the `type constructor' (CCT p m a) to the type w: type aliases can't --- be partially applied. But we can treat the type (NCCT p m a w) that way.-newtype NCCT p m a w = NCCT{unNCCT :: CCT p m a w}--pp :: Typeable w => Prompt PP m w-pp = (inj, prj)- where- inj = PP- prj (PP c) = maybe Nothing (Just . unNCCT) (gcast (NCCT c))---- | The same as PP but with the phantom parameter c--- The parameter is useful to statically enforce various constrains--- (statically pass some information between shift and reset)--- The prompt PP is too `dynamic': all errors are detected dynamically--- See Generator2.hs for an example-data PM c m x = forall w. Typeable w => PM (CCT (PM c) m x w)--pm :: Typeable w => Prompt (PM c) m w-pm = (inj, prj)- where- inj = PM- prj (PM c) = maybe Nothing (Just . unNCCT) (gcast (NCCT c))---- | Open set of answer types, with an additional distinction (given by--- integer identifiers)--- This prompt flavor corresponds to the prompts in the Dybvig, Peyton-Jones,--- Sabry framework (modulo the Typeable constraint).--data PD m x = forall w. Typeable w => PD Int (CCT PD m x w)--newPrompt :: Typeable w => Int -> Prompt PD m w-newPrompt mark = (inj, prj)- where- inj = PD mark- prj (PD mark' c) | mark' == mark, - Just (NCCT x) <- gcast (NCCT c) = Just x- prj _ = Nothing---- | It is often helpful, for clarity of error messages, to specify the --- answer-type associated with the prompt explicitly (rather than relying --- on the type inference to figure that out). The following function--- is useful for that purpose.-as_prompt_type :: Prompt p m w -> w -> Prompt p m w-as_prompt_type = const