很难问这个问题,因为我不知道在这种情况下要使用的确切术语。我将尝试通过遇到的确切问题表达自己的看法:
gogol
库集通过使用Proxy
在类型级别公开了很多权限
-gogol
中的许多功能在此“权限列表”上都是多态的,例如newEnv
,其功能签名如下所示,其中s
应该是以下内容的列表这些代理。
newEnv :: (MonadIO m, MonadCatch m, AllowScopes s) => m (Env s)
现在,这是应该提供此s
类型级别参数的方式:
import Network.Google (allow, (!), newEnv, Env)
import Network.Google.Sheets (driveScope, spreadsheetsScope)
type MyScopes = '[ "https://www.googleapis.com/auth/drive"
, "https://www.googleapis.com/auth/spreadsheets"
]
myEnv :: (MonadIO m, MonadCatch m) => Env MyScopes
mEnv = Network.Google.allow (driveScope ! spreadsheetScope) newEnv
-- or --
myEnv :: (MonadIO m, MonadCatch m) => Env MyScopes
mEnv = Network.Google.allow (Proxy :: Proxy MyScopes) newEnv
是否注意到上面的代码片段中的重复内容?即使gogol
库提供了driveScope
和spreadsheetsScope
,我还是不得不再次输入它们。有什么办法可以做以下等同的概念:
myEnv :: (MonadIO m, MonadCatch m) => Env (driveScope ! spreadsheetScope)
答案 0 :(得分:0)
据我所知,这是不可能的-您无法以所需的方式访问声明值的类型。
正如@Daniel Wagner所评论的那样,这些库应该导出类型同义词-您可以向the repository发出拉取请求,但是这种样式已在所有各种库中使用,因此可能需要一些工作。 / p>
如果您不介意在本地拥有类型的副本,则可以执行另一种类型级别的编程以避免重复:
{-# LANGUAGE DataKinds, TypeFamilies, TypeOperators, TypeApplications #-}
...
import Network.Gogol.Auth.Scope (Nub, (++))
-- Type-level append, used by !
type family a !! b where
xs !! ys = Nub (xs ++ ys)
myEnv :: (MonadIO m, MonadCatch m) => Env (DriveScope !! SpreadsheetScope)
-- Here, @ just lets you pass in type parameters that don't appear in the body
mEnv = Network.Google.allow (Proxy @(DriveScope !! SpreadsheetScope)) newEnv
type DriveScope = '[...]
type SpreadsheetScope = '[...]
但这仍然意味着您要自己重复一遍。