packages feed

typecheck-plugin-nat-simple-0.1.0.0: src/Control/Monad/StateT.hs

{-# LANGUAGE BlockArguments, TupleSections #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Control.Monad.StateT (StateT(..), lift) where

import Control.Applicative (Alternative(..))
import Control.Arrow (first)
import Control.Monad (MonadPlus, (>=>))

---------------------------------------------------------------------------

-- * NEWTYPE STATE T
-- * INSTANCE
--	+ FUNCTOR
--	+ APPLICATIVE AND ALTERNATIVE
--	+ MONAD AND MONAD PLUS

---------------------------------------------------------------------------
-- NEWTYPE STATE T
---------------------------------------------------------------------------

newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }

lift :: Functor m => m a -> StateT s m a
lift m = StateT \s -> (, s) <$> m

---------------------------------------------------------------------------
-- INSTANCE
---------------------------------------------------------------------------

-- FUNCTOR

instance Functor m => Functor (StateT s m) where
	f `fmap` StateT k = StateT $ ((f `first`) <$>) . k

-- APPLICATIVE AND ALTERNATIVE

instance Monad m => Applicative (StateT s m) where
	pure = StateT . (pure .) . (,)
	StateT kf <*> mx = StateT $ kf >=> \(f, s') -> (f <$> mx) `runStateT` s'

instance MonadPlus m => Alternative (StateT s m) where
	empty = StateT $ const empty
	StateT k <|> StateT l = StateT $ (<|>) <$> k <*> l

-- MONAD AND MONAD PLUS

instance Monad m => Monad (StateT s m) where
	StateT k >>= f = StateT $ k >=> \(x, s') -> f x `runStateT` s'

instance MonadPlus m => MonadPlus (StateT s m)