| 1 |
{-# OPTIONS_GHC -fglasgow-exts -fno-warn-unused-binds #-} |
|---|
| 2 |
|
|---|
| 3 |
{-| |
|---|
| 4 |
Continuation with shift and reset operators. |
|---|
| 5 |
|
|---|
| 6 |
> The Road goes ever on and on |
|---|
| 7 |
> Down from the door where it began. |
|---|
| 8 |
> Now far ahead the Road has gone, |
|---|
| 9 |
> And I must follow, if I can... |
|---|
| 10 |
-} |
|---|
| 11 |
|
|---|
| 12 |
module Pugs.Cont ( |
|---|
| 13 |
callCCT, shift, reset, shiftT, resetT, |
|---|
| 14 |
module Control.Monad.Cont, |
|---|
| 15 |
) where |
|---|
| 16 |
|
|---|
| 17 |
import qualified Control.Monad.Cont as C (lift) |
|---|
| 18 |
import Control.Monad.Cont (mapContT, withContT, mapCont, withCont, Cont(..), ContT(..), MonadCont(..)) |
|---|
| 19 |
|
|---|
| 20 |
-- Cont' m a is the type of a continuation expecting an a within the |
|---|
| 21 |
-- continuation monad Cont m |
|---|
| 22 |
type Cont' m a = forall r. a -> m r |
|---|
| 23 |
|
|---|
| 24 |
callCCT :: forall a m. MonadCont m => (Cont' m a -> m a) -> m a |
|---|
| 25 |
callCCT f = callCC f' where |
|---|
| 26 |
f' :: (a -> m (EmptyMonad m)) -> m a |
|---|
| 27 |
f' g = f g' where |
|---|
| 28 |
g' :: a -> m b |
|---|
| 29 |
g' = (=<<) runEmptyMonad . g |
|---|
| 30 |
|
|---|
| 31 |
-- ghc doesn't allow something like m (forall c. m c) |
|---|
| 32 |
newtype EmptyMonad m = EmptyMonad { runEmptyMonad :: forall c. m c } |
|---|
| 33 |
|
|---|
| 34 |
-- shift/reset for the Cont monad |
|---|
| 35 |
shift :: ((a -> Cont s r) -> Cont r r) -> Cont r a |
|---|
| 36 |
shift e = Cont $ \k -> e (return . k) `runCont` id |
|---|
| 37 |
|
|---|
| 38 |
reset :: Cont a a -> Cont r a |
|---|
| 39 |
reset e = return $ e `runCont` id |
|---|
| 40 |
|
|---|
| 41 |
-- shiftT/resetT for the ContT monad transformer |
|---|
| 42 |
shiftT :: Monad m => ((a -> ContT r m s) -> ContT s m s) -> ContT s m a |
|---|
| 43 |
shiftT e = ContT $ \k -> e (C.lift . k) `runContT` return |
|---|
| 44 |
|
|---|
| 45 |
resetT :: Monad m => ContT a m a -> ContT r m a |
|---|
| 46 |
resetT e = C.lift $ e `runContT` return |
|---|
| 47 |
|
|---|