airship-0.9.0: src/Airship/RST.hs
{-
This file is copyright (c) 2009, the Snap Framework authors,
and Patrick Thomson (for the Airship project).
Used under the three-clause BSD license, the text of which may be
found in the LICENSE file in the Airship root.
-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-
RST is like the RWST monad, but has no Writer instance, as Writer leaks space.
This file is almost entirely lifted from the Snap framework's implementation.
-}
module Airship.RST
( RST (..)
, evalRST
, execRST
, mapRST
, withRST
, failure
) where
import Control.Applicative (Alternative (..),
Applicative (..))
import Control.Category ((.))
import Control.Monad (MonadPlus (..), ap)
import Control.Monad.Base (MonadBase (..))
import Control.Monad.Reader (MonadReader (..))
import Control.Monad.State.Class (MonadState (..))
import Control.Monad.Trans (MonadIO (..), MonadTrans (..))
import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
MonadTransControl (..),
defaultLiftBaseWith,
defaultRestoreM)
import Data.Either
import Prelude (Functor (..), Monad (..), seq,
($), ($!))
newtype RST r s e m a = RST { runRST :: r -> s -> m (Either e a, s) }
evalRST :: Monad m => RST r s e m a -> r -> s -> m (Either e a)
evalRST m r s = do
(res, _) <- runRST m r s
return $! res
{-# INLINE evalRST #-}
execRST :: Monad m => RST r s e m a -> r -> s -> m s
execRST m r s = do
(_,!s') <- runRST m r s
return $! s'
{-# INLINE execRST #-}
withRST :: Monad m => (r' -> r) -> RST r s e m a -> RST r' s e m a
withRST f m = RST $ \r' s -> runRST m (f r') s
{-# INLINE withRST #-}
instance (Monad m) => MonadReader r (RST r s e m) where
ask = RST $ \r s -> return $! (Right r,s)
local f m = RST $ \r s -> runRST m (f r) s
-- Terrible hack to work around the fact that Functor isn't a superclass
-- of Monad on GHC 7.8. TODO kill this when 7.8 support is dropped
#if __GLASGOW_HASKELL__ == 708
instance (Monad m) => Functor (RST r s e m) where
fmap f m = RST $ \r s -> runRST m r s >>= helper where
helper (a, s') = case a of
(Left l) -> return $! (Left l, s')
(Right r) -> return $! (Right $ f r, s')
#else
instance (Functor m) => Functor (RST r s e m) where
fmap f m = RST $ \r s -> fmap (\(a,s') -> (fmap f a, s')) $ runRST m r s
#endif
instance Monad m => Applicative (RST r s e m) where
pure = return
(<*>) = ap
instance MonadPlus m => Alternative (RST r s e m) where
empty = mzero
(<|>) = mplus
instance (Monad m) => MonadState s (RST r s e m) where
get = RST $ \_ s -> return $! (Right s,s)
put x = RST $ \_ _ -> return $! (Right (),x)
state act = RST $ \_ s -> do
let (res, !s') = act s
return $! (Right res, s')
mapRST :: (m (Either e a, s) -> n (Either e b, s)) -> RST r s e m a -> RST r s e n b
mapRST f m = RST $ \r s -> f (runRST m r s)
rwsBind :: Monad m =>
RST r s e m a
-> (a -> RST r s e m b)
-> RST r s e m b
rwsBind m f = RST go
where
go r !s = do
(a, !s') <- runRST m r s
case a of
Left e -> return $! (Left e, s')
Right a' -> runRST (f a') r s'
{-# INLINE rwsBind #-}
instance (Monad m) => Monad (RST r s e m) where
return a = RST $ \_ s -> return $! (Right a, s)
(>>=) = rwsBind
fail msg = RST $ \_ _ -> fail msg
instance (MonadPlus m) => MonadPlus (RST r s e m) where
mzero = RST $ \_ _ -> mzero
m `mplus` n = RST $ \r s -> runRST m r s `mplus` runRST n r s
instance (MonadIO m) => MonadIO (RST r s e m) where
liftIO = lift . liftIO
instance MonadTrans (RST r s e) where
lift m = RST $ \_ s -> do
a <- m
return $ s `seq` (Right a, s)
instance MonadBase b m => MonadBase b (RST r s e m) where
liftBase = lift . liftBase
instance MonadBaseControl b m => MonadBaseControl b (RST r s e m) where
type StM (RST r s e m) a = ComposeSt (RST r s e) m a
liftBaseWith = defaultLiftBaseWith
restoreM = defaultRestoreM
{-# INLINE liftBaseWith #-}
{-# INLINE restoreM #-}
instance MonadTransControl (RST r s e) where
type StT (RST r s e) a = (Either e a, s)
liftWith f = RST $ \r s -> do
res <- f $ \(RST g) -> g r s
return $! (Right res, s)
restoreT k = RST $ \_ _ -> k
{-# INLINE liftWith #-}
{-# INLINE restoreT #-}
failure :: Monad m => e -> RST r s e m a
failure e = RST $ \_ s -> return $! (Left e, s)