如何将代理值恢复为类型级别?

时间:2018-09-11 09:17:31

标签: haskell

很难问这个问题,因为我不知道在这种情况下要使用的确切术语。我将尝试通过遇到的确切问题表达自己的看法:

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库提供了driveScopespreadsheetsScope,我还是不得不再次输入它们。有什么办法可以做以下等同​​的概念:

myEnv :: (MonadIO m, MonadCatch m) => Env (driveScope ! spreadsheetScope)

1 个答案:

答案 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 = '[...]

但这仍然意味着您要自己重复一遍。