packages feed

monad-supply-0.9: src/Control/Monad/Supply.hs

{-# LANGUAGE CPP                        #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE FunctionalDependencies     #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE UndecidableInstances       #-}

-- | Support for computations which consume values from a (possibly infinite)
-- supply. See <http://www.haskell.org/haskellwiki/New_monads/MonadSupply> for
-- details.

module Control.Monad.Supply
    ( MonadSupply(..)
    , SupplyT
    , Supply
    , evalSupplyT
    , evalSupply
    , runSupplyT
    , runSupply
    , supplies
    ) where

import           Control.Monad             (replicateM)
import           Control.Monad.Except      (ExceptT, MonadError, throwError, catchError)
import           Control.Monad.Fix         (MonadFix)
import           Control.Monad.IO.Class    (MonadIO)
import           Control.Monad.Reader      (ReaderT)
import           Control.Monad.State       (StateT, get, gets, put, evalStateT, runStateT)
import           Control.Monad.Trans       (MonadTrans, lift)
import           Control.Monad.Trans.Maybe (MaybeT)
import           Control.Monad.Writer      (WriterT)
#if !MIN_VERSION_base(4,11,0)
import           Control.Monad.Fail        (MonadFail)
import           Data.Semigroup            (Semigroup, (<>))
#endif

import qualified Control.Monad.Trans.State.Lazy as LazyState


class Monad m => MonadSupply s m | m -> s where
    supply :: m s
    peek :: m s
    exhausted :: m Bool

-- | Supply monad transformer.
newtype SupplyT s m a = SupplyT { unSupplyT :: StateT [s] m a }
    deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MonadFix)

instance MonadError e m => MonadError e (SupplyT s m) where
    throwError = lift . throwError
    catchError m h =
        SupplyT $ LazyState.liftCatch catchError (unSupplyT m) (unSupplyT . h)

-- | Supply monad.
newtype Supply s a = Supply (SupplyT s Maybe a)
    deriving (Functor, Applicative, Monad, MonadSupply s, MonadFix)

instance MonadFail m => MonadSupply s (SupplyT s m) where
    supply = SupplyT $ do
        (x:xs) <- get
        put xs
        return x
    peek = SupplyT $ gets head
    exhausted = SupplyT $ gets null

-- Monad transformer instances
instance (MonadSupply s m) => MonadSupply s (ExceptT e m) where
    supply = lift supply
    peek = lift peek
    exhausted = lift exhausted

instance MonadSupply s m => MonadSupply s (StateT st m) where
    supply = lift supply
    peek = lift peek
    exhausted = lift exhausted

instance MonadSupply s m => MonadSupply s (ReaderT r m) where
    supply = lift supply
    peek = lift peek
    exhausted = lift exhausted

instance MonadSupply s m => MonadSupply s (MaybeT m) where
    supply = lift supply
    peek = lift peek
    exhausted = lift exhausted

instance (Monoid w, MonadSupply s m) => MonadSupply s (WriterT w m) where
    supply = lift supply
    peek = lift peek
    exhausted = lift exhausted

instance Semigroup a => Semigroup (Supply s a) where
    m1 <> m2 = (<>) <$> m1 <*> m2

instance (Semigroup a, Monoid a) => Monoid (Supply s a) where
    mempty = return mempty
    m1 `mappend` m2 = m1 <> m2

-- | Get n supplies.
supplies :: MonadSupply s m => Int -> m [s]
supplies n = replicateM n supply

evalSupplyT :: Monad m => SupplyT s m a -> [s] -> m a
evalSupplyT (SupplyT s) = evalStateT s

evalSupply :: Supply s a -> [s] -> Maybe a
evalSupply (Supply s) = evalSupplyT s

runSupplyT :: Monad m => SupplyT s m a -> [s] -> m (a,[s])
runSupplyT (SupplyT s) = runStateT s

runSupply :: Supply s a -> [s] -> Maybe (a,[s])
runSupply (Supply s) = runSupplyT s