{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
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
#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)