newtypeServeFor site param a = ServeFor (ReaderT (ServiceContextsiteparam) (HandlerForsite) a)
该类型是一个多参数类型,现在需要对其写个liftS,使得ServeFor可以提升到其他Monad
1 2 3 4 5
classMonad m => MonadServe site param m where liftS :: ServeFor site param a -> m a instanceMonadServe site param (DbServeForsiteparam) where liftS = DbServeFor . lift
liftSDBS :: forall site param a. ServeFor site param a -> DbServeFor site param a liftSDBS = liftS
这种方式比较冗余,为了添加约束需要另外定义一个函数
方式2:调用的时候提供类型推导
1 2 3 4 5 6 7 8
test :: DbServeFor site param a test po domain = do ServiceContext userId now _ <- (liftS ctx :: DbServeFor site param)
-- 添加TypeApplications test2 :: DbServeFor site param a test2 po domain = do ServiceContext userId now _ <- liftS @site @param ctx
方式3:Scoped Type Variables(推荐)
在定义class的时候就添加约束
1 2 3 4 5 6 7 8 9
classMonad m => MonadServe m where typeServeSite m typeServeParam m liftS :: ServeFor (ServeSite m) (ServeParam m) a -> m a instanceMonadServe (DbServeForsiteparam) where typeServeSite (DbServeForsiteparam) = site typeServeParam (DbServeForsiteparam) = param liftS = DbServeFor . lift
type ServeSite m和type ServeParam m不仅仅是为了转移了class的参数,还说明了这两个属性从m推导。
1 2 3 4 5 6 7 8 9
-- site param m各自独立,没有关系 classMonad m => MonadServe site param m where liftS :: ServeFor site param a -> m a
-- ServeSite m和ServeParam m可以获取m的属性 classMonad m => MonadServe m where typeServeSite m typeServeParam m liftS :: ServeFor (ServeSite m) (ServeParam m) a -> m a