Haskell 如何让GHC将我的孤立实例“HasServer”和“HasClient”应用于“AuthProtect”?
我使用来自的Haskell 如何让GHC将我的孤立实例“HasServer”和“HasClient”应用于“AuthProtect”?,haskell,instance,servant,orphan,Haskell,Instance,Servant,Orphan,我使用来自的AuthProtectcombinator。那里没有太多的代码,实例HasServer(AuthProtect标记)在servant server中,而insanceHasClient(AuthProtect标记)在您使用的任何servant客户端中 我使用servant snap代替servant server和一个自定义HasClient实现obelisk项目,项目结构由三个阴谋包组成: 前端(由ghcjs编制) 通用(由ghcjs和ghc编制) 后端(由ghc编译) 我曾经
AuthProtect
combinator。那里没有太多的代码,实例HasServer(AuthProtect标记)
在servant server
中,而insanceHasClient(AuthProtect标记)
在您使用的任何servant客户端中
我使用servant snap
代替servant server
和一个自定义HasClient
实现obelisk
项目,项目结构由三个阴谋包组成:
- 前端(由ghcjs编制)
- 通用(由ghcjs和ghc编制)
- 后端(由ghc编译)
AuthProtect
实现,以及common
包中的实例。但是,由于ghcjs,common
既不能依赖于servant snap
也不能依赖于snap core
现在我将HasServer
实例移动到后端。。。没问题,对吧?错。一旦HasServer
实例成为孤立实例,ghc将不再正确解析我的api类型。就好像孤儿实例根本不存在一样
为什么呢
有什么,我能做吗?实例是全局的。。。理论上。实际上,为了支持单独编译,它们通过导入进行传播。因此,从使用实例的模块导入定义实例的模块。以可传递的方式导入它已经足够好了,即导入一个模块,该模块导入一个模块,该模块导入定义实例的模块。这两种方法中的任何一种都可以解决我的问题:
instance HasServer api context m => HasServer (AuthProtect "jwt" :> api) context m where
type ServerT (AuthProtect "jwt" :> api) context m =
String -> ServerT api context m
hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt . s
route (Proxy :: Proxy (AuthProtect "jwt" :> api)) context subserver =
route (Proxy :: Proxy api) context (subserver `addAuthCheck` withRequest authCheck)
where
authCheck :: Request -> DelayedM m String
authCheck =
liftIO . evalSnap (pure "account info")
(\x -> pure $! (x `seq` ()))
(\f -> let !_ = f 0 in pure ())
如果出于某种原因我不想专门从事AuthProtect“jwt”
,那么我必须提供约束KnownSymbol标记
instance (KnownSymbol tag, HasServer api context m) => HasServer (AuthProtect tag :> api) context m where
type ServerT (AuthProtect tag :> api) context m =
String -> ServerT api context m
hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt . s
route (Proxy :: Proxy (AuthProtect tag :> api)) context subserver =
route (Proxy :: Proxy api) context (subserver `addAuthCheck` withRequest authCheck)
where
authCheck :: Request -> DelayedM m String
authCheck =
liftIO . evalSnap (pure "account info")
(\x -> pure $! (x `seq` ()))
(\f -> let !_ = f 0 in pure ())
这也是我的假设。我已经导入了定义孤立实例的模块。也许我会尝试用一个最小的例子来说明这种行为。@ruben.moor在这样的问题中,一个最小的复制例子总是受欢迎的。这些最小的例子可以创造奇迹。我通过将
AuthProtect标记
替换为AuthProtect“jwt”
解决了我的问题。如果我想保持它的通用性,我必须在实例约束中添加“KnownSymbol标记”。