代码之家  ›  专栏  ›  技术社区  ›  The Oddler

Haskell Servant:如何在使用泛型时为路由加前缀?

  •  0
  • The Oddler  · 技术社区  · 4 年前

    我使用的是Servant泛型,路由的数据类型为:

    data Routes route = Routes
      { getLiveness :: route :- GetLiveness,
        getReadiness :: route :- GetReadiness,
    
        getAuthVerifyEmailToken :: route :- GetAuthVerifyEmailToken,
        postAuthEmail :: route :- PostAuthEmail,
        ...
      }
      deriving (Generic)
    
    type BackendPrefix = "backend"
    
    type AuthPrefix = "auth"
    
    type GetLiveness = BackendPrefix :> "liveness" :> Get '[JSON] Text
    
    type GetReadiness = BackendPrefix :> "readiness" :> Get '[JSON] Text
    
    type GetAuthVerifyEmailToken = AuthPrefix :> "verify" :> "email" :> Capture "token" JWT :> RedirectResponse '[PlainText] NoContent
    
    type PostAuthEmail = AuthPrefix :> "email" :> ReqBody '[JSON] AuthEmailRequest :> PostNoContent
    

    前两个使用相同的前缀 "backend" ,所有其他的都有一个 "auth" 前缀

    但是,我现在想更改 "auth “backend/auth”的前缀。所以我尝试更改:

    type AuthPrefix = BackendPrefix :> "auth"

    这会导致一个错误

    >     • Expected a type, but
    >       ‘"auth"’ has kind
    >       ‘ghc-prim-0.6.1:GHC.Types.Symbol’
    >     • In the second argument of ‘(:>)’, namely ‘"auth"’
    >       In the type ‘BackendPrefix :> "auth"’
    >       In the type declaration for ‘AuthPrefix’
    >    |
    > 34 | type AuthPrefix = BackendPrefix :> "auth"
    >    |          
    

    所以我在谷歌上搜索了一下,发现你可以 this 不使用泛型时,可以执行以下操作:

    type APIv1 = "api" :> "v1" :> API
    

    但我不知道如何用仿制药做到这一点。

    我想还有两个问题:

    1. 上面的错误是什么意思?我能用这样的方法吗 type AuthPrefix=后端前缀:>“auth” 创建一个更复杂的前缀?
    2. 当在Servant中使用泛型时,有没有办法用一个前缀给一些路由加前缀,用不同的前缀给其他路由加前缀?
    0 回复  |  直到 4 年前
        1
  •  3
  •   danidiaz    4 年前

    的定义 :>

    data (path :: k) :> (a :: *)
    

    注意,正确的部分必须有种类 * ,也称为 Type 。这是“正常”的Haskell类型,比如 Int Bool 提升了价值观。

    但是,在类型级表达式中 BackendPrefix :> "auth" 那种 "auth" Symbol ,这是类型级字符串的类型。种类不匹配,这会导致类型错误。

    (你可能会想,为什么会这样 "foo" :> "bar" :> Post '[JSON] User 工作吗?原因是一个完全应用 Post 有善良 类型 ,一个完全应用的 :> 也有善良 类型 :> 与右翼的同事,比如 "foo" :> ("bar" :> Post '[JSON] User) ,所以一切都结束了。)

    解决方案?也许给予 AuthPrefix 一个类型参数,比如

    type AuthPrefix restofpath = BackendPrefix :> "auth" :> restofpath
    

    这样我们就不会在 象征

    我们必须使用 AuthPrefix 现在有点不同:

     AuthPrefix ("email" :> ReqBody '[JSON] AuthEmailRequest :> PostNoContent)
    

    这是因为新定义已经考虑到应用 :> 到路径的其余部分。

        2
  •  1
  •   Joseph Sible-Reinstate Monica    4 年前

    :> infixr 4 ,这意味着它是正确的联想。考虑这种类型:

    type GetFoo = "backend" :> "auth" :> "foo" :> Get '[JSON] Text
    

    它被解释为您将其插入括号,如下所示:

    type GetFoo = "backend" :> ("auth" :> ("foo" :> Get '[JSON] Text))
    

    使用您尝试过的类型同义词,它会变成这样的括号:

    type GetFoo = ("backend" :> "auth") :> ("foo" :> Get '[JSON] Text)
    

    这显然不是一回事,事实上甚至都不成立。


    为了帮助理解,请考虑以下没有高级类型的普通Haskell代码:

    xs = 1:2:3:4:5:6:[]
    ys = 1:2:4:8:16:32:[]
    

    现在想象一下你试着写这篇文章:

    zs = 1:2
    xs = zs:3:4:5:6:[]
    ys = zs:4:8:16:32:[]
    

    它不起作用的原因与您不能使用类型同义词的原因完全相同。


    最后一个例子:

    x = 2 ^ 3 ^ 2 -- evaluates to 2 ^ (3 ^ 2) = 512
    
    y = 2 ^ 3
    x = y ^ 2 -- evaluates to (2 ^ 3) ^ 2 = 64
    
    推荐文章