2015-05-02 16:46:43 +02:00
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
|
|
{-# LANGUAGE FunctionalDependencies #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
{-# LANGUAGE RankNTypes #-}
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
{-# LANGUAGE TypeOperators #-}
|
|
|
|
{-# LANGUAGE UndecidableInstances #-}
|
2016-04-21 13:31:51 +02:00
|
|
|
module Servant.Utils.Enter where
|
2015-05-02 16:46:43 +02:00
|
|
|
|
|
|
|
import qualified Control.Category as C
|
|
|
|
import Control.Monad.Identity
|
|
|
|
import Control.Monad.Morph
|
|
|
|
import Control.Monad.Reader
|
|
|
|
import qualified Control.Monad.State.Lazy as LState
|
|
|
|
import qualified Control.Monad.State.Strict as SState
|
|
|
|
import qualified Control.Monad.Writer.Lazy as LWriter
|
|
|
|
import qualified Control.Monad.Writer.Strict as SWriter
|
|
|
|
import Data.Typeable
|
2016-03-01 19:25:04 +01:00
|
|
|
import Prelude ()
|
2016-03-01 12:41:24 +01:00
|
|
|
import Prelude.Compat
|
|
|
|
|
2015-05-02 16:46:43 +02:00
|
|
|
import Servant.API
|
|
|
|
|
|
|
|
class Enter typ arg ret | typ arg -> ret, typ ret -> arg where
|
|
|
|
enter :: arg -> typ -> ret
|
|
|
|
|
|
|
|
-- ** Servant combinators
|
|
|
|
instance ( Enter typ1 arg1 ret1, Enter typ2 arg2 ret2
|
|
|
|
, arg1 ~ arg2
|
|
|
|
) => Enter (typ1 :<|> typ2) arg1 (ret1 :<|> ret2) where
|
|
|
|
enter e (a :<|> b) = enter e a :<|> enter e b
|
|
|
|
|
|
|
|
instance (Enter b arg ret) => Enter (a -> b) arg (a -> ret) where
|
|
|
|
enter arg f a = enter arg (f a)
|
|
|
|
|
|
|
|
-- ** Useful instances
|
|
|
|
|
2015-05-03 01:28:13 +02:00
|
|
|
-- | A natural transformation from @m@ to @n@. Used to `enter` particular
|
|
|
|
-- datatypes.
|
2015-05-02 16:46:43 +02:00
|
|
|
newtype m :~> n = Nat { unNat :: forall a. m a -> n a} deriving Typeable
|
|
|
|
|
|
|
|
instance C.Category (:~>) where
|
|
|
|
id = Nat id
|
|
|
|
Nat f . Nat g = Nat (f . g)
|
|
|
|
|
|
|
|
instance Enter (m a) (m :~> n) (n a) where
|
|
|
|
enter (Nat f) = f
|
|
|
|
|
2015-05-03 01:28:13 +02:00
|
|
|
-- | Like `lift`.
|
|
|
|
liftNat :: (Control.Monad.Morph.MonadTrans t, Monad m) => m :~> t m
|
|
|
|
liftNat = Nat Control.Monad.Morph.lift
|
2015-05-02 16:46:43 +02:00
|
|
|
|
|
|
|
runReaderTNat :: r -> (ReaderT r m :~> m)
|
|
|
|
runReaderTNat a = Nat (`runReaderT` a)
|
|
|
|
|
|
|
|
evalStateTLNat :: Monad m => s -> (LState.StateT s m :~> m)
|
|
|
|
evalStateTLNat a = Nat (`LState.evalStateT` a)
|
|
|
|
|
|
|
|
evalStateTSNat :: Monad m => s -> (SState.StateT s m :~> m)
|
|
|
|
evalStateTSNat a = Nat (`SState.evalStateT` a)
|
|
|
|
|
|
|
|
-- | Log the contents of `SWriter.WriterT` with the function provided as the
|
|
|
|
-- first argument, and return the value of the @WriterT@ computation
|
|
|
|
logWriterTSNat :: MonadIO m => (w -> IO ()) -> (SWriter.WriterT w m :~> m)
|
|
|
|
logWriterTSNat logger = Nat $ \x -> do
|
|
|
|
(a, w) <- SWriter.runWriterT x
|
|
|
|
liftIO $ logger w
|
|
|
|
return a
|
|
|
|
|
|
|
|
-- | Like `logWriterTSNat`, but for strict @WriterT@.
|
|
|
|
logWriterTLNat :: MonadIO m => (w -> IO ()) -> (LWriter.WriterT w m :~> m)
|
|
|
|
logWriterTLNat logger = Nat $ \x -> do
|
|
|
|
(a, w) <- LWriter.runWriterT x
|
|
|
|
liftIO $ logger w
|
|
|
|
return a
|
|
|
|
|
|
|
|
-- | Like @mmorph@'s `hoist`.
|
|
|
|
hoistNat :: (MFunctor t, Monad m) => (m :~> n) -> (t m :~> t n)
|
|
|
|
hoistNat (Nat n) = Nat $ hoist n
|
|
|
|
|
2015-05-03 01:28:13 +02:00
|
|
|
-- | Like @mmorph@'s `embed`.
|
2015-05-02 16:46:43 +02:00
|
|
|
embedNat :: (MMonad t, Monad n) => (m :~> t n) -> (t m :~> t n)
|
|
|
|
embedNat (Nat n) = Nat $ embed n
|
|
|
|
|
2015-05-03 01:28:13 +02:00
|
|
|
-- | Like @mmorph@'s `squash`.
|
2015-05-02 16:46:43 +02:00
|
|
|
squashNat :: (Monad m, MMonad t) => t (t m) :~> t m
|
|
|
|
squashNat = Nat squash
|
|
|
|
|
2015-05-03 01:28:13 +02:00
|
|
|
-- | Like @mmorph@'s `generalize`.
|
2015-05-02 16:46:43 +02:00
|
|
|
generalizeNat :: Applicative m => Identity :~> m
|
|
|
|
generalizeNat = Nat (pure . runIdentity)
|