crucible-0.7: src/Lang/Crucible/Utils/StateContT.hs
------------------------------------------------------------------------
-- |
-- Module : Lang.Crucible.Utils.StateContT
-- Description : A monad providing continuations and state.
-- Copyright : (c) Galois, Inc 2013-2014
-- License : BSD3
-- Maintainer : Joe Hendrix <jhendrix@galois.com>
-- Stability : provisional
--
-- This module defines a monad with continuations and state. By using this
-- instead of a MTL StateT and ContT transformer stack, one can have a
-- continuation that implements MonadCont and MonadState, yet never
-- returns the final state. This also wraps MonadST.
------------------------------------------------------------------------
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
module Lang.Crucible.Utils.StateContT
( StateContT(..)
-- * Re-exports
, Control.Monad.Cont.Class.MonadCont(..)
, Control.Monad.State.Class.MonadState(..)
) where
import Control.Monad.Cont.Class (MonadCont(..))
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Reader.Class (MonadReader(..))
import Control.Monad.State.Class (MonadState(..))
import Control.Monad.Trans (MonadTrans(..))
import Control.Monad.Catch ( MonadThrow(..), MonadCatch(..) )
import What4.Utils.MonadST
-- | A monad transformer that provides @MonadCont@ and @MonadState@.
newtype StateContT s r m a
= StateContT { runStateContT :: (a -> s -> m r)
-> s
-> m r
}
fmapStateContT :: (a -> b) -> StateContT s r m a -> StateContT s r m b
fmapStateContT = \f m -> StateContT $ \c -> runStateContT m (\v s -> (c $! f v) s)
{-# INLINE fmapStateContT #-}
applyStateContT :: StateContT s r m (a -> b) -> StateContT s r m a -> StateContT s r m b
applyStateContT = \mf mv ->
StateContT $ \c ->
runStateContT mf (\f -> runStateContT mv (\v s -> (c $! f v) s))
{-# INLINE applyStateContT #-}
returnStateContT :: a -> StateContT s r m a
returnStateContT = \v -> seq v $ StateContT $ \c -> c v
{-# INLINE returnStateContT #-}
bindStateContT :: StateContT s r m a -> (a -> StateContT s r m b) -> StateContT s r m b
bindStateContT = \m n -> StateContT $ \c -> runStateContT m (\a -> runStateContT (n a) c)
{-# INLINE bindStateContT #-}
instance Functor (StateContT s r m) where
fmap = fmapStateContT
instance Applicative (StateContT s r m) where
pure = returnStateContT
(<*>) = applyStateContT
instance Monad (StateContT s r m) where
(>>=) = bindStateContT
instance MonadFail m => MonadFail (StateContT s r m) where
fail = \msg -> StateContT $ \_ _ -> fail msg
instance MonadCont (StateContT s r m) where
callCC f = StateContT $ \c -> runStateContT (f (\a -> seq a $ StateContT $ \_ s -> c a s)) c
instance MonadState s (StateContT s r m) where
get = StateContT $ \c s -> c s s
put = \s -> seq s $ StateContT $ \c _ -> c () s
state f = StateContT $ \c s -> let (r,s') = f s in (c $! r) $! s'
instance MonadTrans (StateContT s r) where
lift = \m -> StateContT $ \c s -> m >>= \v -> seq v (c v s)
instance MonadIO m => MonadIO (StateContT s r m) where
liftIO = lift . liftIO
instance MonadST s m => MonadST s (StateContT t r m) where
liftST = lift . liftST
instance MonadReader v m => MonadReader v (StateContT s r m) where
ask = lift ask
local f m = StateContT $ \c s -> local f (runStateContT m c s)
instance MonadThrow m => MonadThrow (StateContT s r m) where
throwM e = StateContT (\_k _s -> throwM e)
instance MonadCatch m => MonadCatch (StateContT s r m) where
catch m hdl =
StateContT $ \k s ->
catch
(runStateContT m k s)
(\e -> runStateContT (hdl e) k s)