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

122 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
2016-11-15 21:33:23 +01:00
import Control.Natural
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
import Data.Tagged (Tagged, retag)
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
-- | 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)