{-# LANGUAGE GADTs #-} ------------------------------------------------------------------------------- -- | -- Module : Control.Monad.CC.Seq -- Copyright : (c) R. Kent Dybvig, Simon L. Peyton Jones and Amr Sabry -- License : MIT -- -- Maintainer : Dan Doel -- Stability : Experimental -- Portability : Non-portable (generalized algebraic datatypes) -- -- A monadic treatment of delimited continuations. -- -- Adapted from the paper -- /A Monadic Framework for Delimited Continuations/, -- by R. Kent Dybvig, Simon Peyton Jones and Amr Sabry -- () -- -- This module implements the generalized sequence type used as a stack of -- frames representation of the delimited continuations. module Control.Monad.CC.Seq ( -- * Sequence datatype Seq(..), -- * Sub-sequences SubSeq, appendSubSeq, pushSeq, splitSeq, ) where import Control.Monad.CC.Prompt -- | This is a generalized sequence datatype, parameterized by three types: -- seg : A constructor for segments of the sequence. -- -- ans : the type resulting from applying all the segments of the sequence. -- Also used as a region parameter. -- -- a : The type expected as input to the sequence of segments. data Seq seg ans a where EmptyS :: Seq seg ans ans PushP :: Prompt ans a -> Seq seg ans a -> Seq seg ans a PushSeg :: seg ans a b -> Seq seg ans b -> Seq seg ans a -- | A type representing a sub-sequence, which may be appended to a sequence -- of appropriate type. It represents a sequence that takes values of type -- a to values of type b, and may be pushed onto a sequence that takes values -- of type b to values of type ans. type SubSeq seg ans a b = Seq seg ans b -> Seq seg ans a -- | The null sub-sequence emptySubSeq :: SubSeq seg ans a a emptySubSeq = id -- | Concatenate two subsequences appendSubSeq :: SubSeq seg ans a b -> SubSeq seg ans b c -> SubSeq seg ans a c appendSubSeq = (.) -- | Push a sub-sequence onto the front of a sequence pushSeq :: SubSeq seg ans a b -> Seq seg ans b -> Seq seg ans a pushSeq = ($) -- | Splits a sequence at the given prompt into a sub-sequence, and -- the rest of the sequence splitSeq :: Prompt ans b -> Seq seg ans a -> (SubSeq seg ans a b, Seq seg ans b) splitSeq _ EmptyS = error "Prompt was not found on the stack." splitSeq p (PushP p' sk) = case eqPrompt p' p of EQU -> (emptySubSeq, sk) NEQ -> case splitSeq p sk of (subk, sk') -> (appendSubSeq (PushP p') subk, sk') splitSeq p (PushSeg seg sk) = case splitSeq p sk of (subk, sk') -> (appendSubSeq (PushSeg seg) subk, sk')