servant/servant/src/Servant/Utils/Enter.hs

123 lines
3.9 KiB
Haskell
Raw Normal View History

2015-05-02 16:46:43 +02:00
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
2017-10-01 18:20:09 +02:00
module Servant.Utils.Enter {-# DEPRECATED "Use hoistServer or hoistServerWithContext from servant-server" #-} (
2016-11-15 21:33:23 +01:00
module Servant.Utils.Enter,
-- * natural-transformation re-exports
(:~>)(..),
) where
2015-05-02 16:46:43 +02:00
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
2018-03-11 16:58:31 +01:00
import Control.Natural
import Data.Tagged
(Tagged, retag)
import Prelude ()
2016-03-01 12:41:24 +01:00
import Prelude.Compat
2015-05-02 16:46:43 +02:00
import Servant.API
-- | Helper type family to state the 'Enter' symmetry.
2017-04-28 13:31:57 +02:00
type family Entered m n api where
Entered m n (a -> api) = a -> Entered m n api
Entered m n (m a) = n a
2017-04-28 13:31:57 +02:00
Entered m n (api1 :<|> api2) = Entered m n api1 :<|> Entered m n api2
Entered m n (Tagged m a) = Tagged n a
2017-04-28 13:31:57 +02:00
class
( Entered m n typ ~ ret
, Entered n m ret ~ typ
) => Enter typ m n ret | typ m n -> ret, ret m n -> typ, ret typ m -> n, ret typ n -> m
2017-04-28 13:31:57 +02:00
where
-- | Map the leafs of an API type.
2017-04-28 13:55:13 +02:00
enter :: (m :~> n) -> typ -> ret
2015-05-02 16:46:43 +02:00
-- ** Servant combinators
2017-04-28 13:31:57 +02:00
instance
( Enter typ1 m1 n1 ret1, Enter typ2 m2 n2 ret2
2017-04-28 13:31:57 +02:00
, m1 ~ m2, n1 ~ n2
, Entered m1 n1 (typ1 :<|> typ2) ~ (ret1 :<|> ret2)
, Entered n1 m1 (ret1 :<|> ret2) ~ (typ1 :<|> typ2)
2017-04-28 13:31:57 +02:00
) => Enter (typ1 :<|> typ2) m1 n1 (ret1 :<|> ret2)
where
2015-05-02 16:46:43 +02:00
enter e (a :<|> b) = enter e a :<|> enter e b
2017-04-28 13:31:57 +02:00
instance
( Enter typ m n ret
, Entered m n (a -> typ) ~ (a -> ret)
2017-04-28 13:31:57 +02:00
, Entered n m (a -> ret) ~ (a -> typ)
) => Enter (a -> typ) m n (a -> ret)
2017-04-28 13:31:57 +02:00
where
2015-05-02 16:46:43 +02:00
enter arg f a = enter arg (f a)
-- ** Leaf instances
2015-05-02 16:46:43 +02:00
instance
( Entered m n (Tagged m a) ~ Tagged n a
, Entered n m (Tagged n a) ~ Tagged m a
) => Enter (Tagged m a) m n (Tagged n a)
where
enter _ = retag
instance
( Entered m n (m a) ~ n a
, Entered n m (n a) ~ m a
) => Enter (m a) m n (n a)
where
2016-11-15 21:33:23 +01:00
enter (NT f) = f
2015-05-02 16:46:43 +02:00
2015-05-03 01:28:13 +02:00
-- | Like `lift`.
liftNat :: (Control.Monad.Morph.MonadTrans t, Monad m) => m :~> t m
2016-11-15 21:33:23 +01:00
liftNat = NT Control.Monad.Morph.lift
2015-05-02 16:46:43 +02:00
runReaderTNat :: r -> (ReaderT r m :~> m)
2016-11-15 21:33:23 +01:00
runReaderTNat a = NT (`runReaderT` a)
2015-05-02 16:46:43 +02:00
evalStateTLNat :: Monad m => s -> (LState.StateT s m :~> m)
2016-11-15 21:33:23 +01:00
evalStateTLNat a = NT (`LState.evalStateT` a)
2015-05-02 16:46:43 +02:00
evalStateTSNat :: Monad m => s -> (SState.StateT s m :~> m)
2016-11-15 21:33:23 +01:00
evalStateTSNat a = NT (`SState.evalStateT` a)
2015-05-02 16:46:43 +02:00
-- | 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)
2016-11-15 21:33:23 +01:00
logWriterTSNat logger = NT $ \x -> do
2015-05-02 16:46:43 +02:00
(a, w) <- SWriter.runWriterT x
liftIO $ logger w
return a
2017-02-15 18:19:35 +01:00
-- | Like `logWriterTSNat`, but for lazy @WriterT@.
2015-05-02 16:46:43 +02:00
logWriterTLNat :: MonadIO m => (w -> IO ()) -> (LWriter.WriterT w m :~> m)
2016-11-15 21:33:23 +01:00
logWriterTLNat logger = NT $ \x -> do
2015-05-02 16:46:43 +02:00
(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)
2016-11-15 21:33:23 +01:00
hoistNat (NT n) = NT $ hoist n
2015-05-02 16:46:43 +02:00
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)
2016-11-15 21:33:23 +01:00
embedNat (NT n) = NT $ embed n
2015-05-02 16:46:43 +02:00
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
2016-11-15 21:33:23 +01:00
squashNat = NT squash
2015-05-02 16:46:43 +02:00
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
2016-11-15 21:33:23 +01:00
generalizeNat = NT (pure . runIdentity)