swagger2-2.0: src/Data/Swagger/Declare.hs
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Data.Swagger.Declare where
import Prelude ()
import Prelude.Compat
import Control.Monad
import Control.Monad.Trans
import Data.Functor.Identity
import Data.Monoid
-- | A declare monad transformer parametrized by:
--
-- * @d@ — the output to accumulate (declarations);
--
-- * @m@ — the inner monad.
--
-- This monad transformer is similar to both state and writer monad transformers.
-- Thus it can be seen as
--
-- * a restricted append-only version of a state monad transformer or
--
-- * a writer monad transformer with the extra ability to read all previous output.
newtype DeclareT d m a = DeclareT { runDeclareT :: d -> m (d, a) }
deriving (Functor)
instance (Applicative m, Monad m, Monoid d) => Applicative (DeclareT d m) where
pure x = DeclareT (\_ -> pure (mempty, x))
DeclareT df <*> DeclareT dx = DeclareT $ \d -> do
~(d', f) <- df d
~(d'', x) <- dx (d <> d')
return (d' <> d'', f x)
instance (Applicative m, Monad m, Monoid d) => Monad (DeclareT d m) where
return x = DeclareT (\_ -> pure (mempty, x))
DeclareT dx >>= f = DeclareT $ \d -> do
~(d', x) <- dx d
~(d'', y) <- runDeclareT (f x) (d <> d')
return (d' <> d'', y)
instance Monoid d => MonadTrans (DeclareT d) where
lift m = DeclareT (\_ -> (,) mempty `liftM` m)
-- |
-- Definitions of @declare@ and @look@ must satisfy the following laws:
--
-- [/monoid homomorphism (mempty)/]
-- @'declare' mempty == return ()@
--
-- [/monoid homomorphism (mappend)/]
-- @'declare' x >> 'declare' y == 'declare' (x <> y)@
-- for every @x@, @y@
--
-- [/@declare@-@look@/]
-- @'declare' x >> 'look' == 'fmap' (<> x) 'look' <* 'declare' x@
-- for every @x@
--
-- [/@look@ as left identity/]
-- @'look' >> m == m@
-- for every @m@
class (Applicative m, Monad m) => MonadDeclare d m | m -> d where
-- | @'declare' x@ is an action that produces the output @x@.
declare :: d -> m ()
-- | @'look'@ is an action that returns all the output so far.
look :: m d
instance (Applicative m, Monad m, Monoid d) => MonadDeclare d (DeclareT d m) where
declare d = DeclareT (\_ -> return (d, ()))
look = DeclareT (\d -> return (mempty, d))
-- | Retrieve a function of all the output so far.
looks :: MonadDeclare d m => (d -> a) -> m a
looks f = f <$> look
-- | Evaluate @'DeclareT' d m a@ computation,
-- ignoring new output @d@.
evalDeclareT :: Monad m => DeclareT d m a -> d -> m a
evalDeclareT (DeclareT f) d = snd `liftM` f d
-- | Execute @'DeclateT' d m a@ computation,
-- ignoring result and only producing new output @d@.
execDeclareT :: Monad m => DeclareT d m a -> d -> m d
execDeclareT (DeclareT f) d = fst `liftM` f d
-- | Evaluate @'DeclareT' d m a@ computation,
-- starting with empty output history.
undeclareT :: (Monad m, Monoid d) => DeclareT d m a -> m a
undeclareT = flip evalDeclareT mempty
-- | A declare monad parametrized by @d@ — the output to accumulate (declarations).
--
-- This monad is similar to both state and writer monads.
-- Thus it can be seen as
--
-- * a restricted append-only version of a state monad or
--
-- * a writer monad with the extra ability to read all previous output.
type Declare d = DeclareT d Identity
-- | Run @'Declare' d a@ computation with output history @d@,
-- producing result @a@ and new output @d@.
runDeclare :: Declare d a -> d -> (d, a)
runDeclare m = runIdentity . runDeclareT m
-- | Evaluate @'Declare' d a@ computation, ignoring output @d@.
evalDeclare :: Declare d a -> d -> a
evalDeclare m = runIdentity . evalDeclareT m
-- | Execute @'Declate' d a@ computation, ignoring result and only
-- producing output @d@.
execDeclare :: Declare d a -> d -> d
execDeclare m = runIdentity . execDeclareT m
-- | Evaluate @'DeclareT' d m a@ computation,
-- starting with empty output history.
undeclare :: Monoid d => Declare d a -> a
undeclare = runIdentity . undeclareT