2

In the Servant docs, we have the following api:

type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
      :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
      :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email

and we can define client functions like so:

api :: Proxy API
api = Proxy

position :<|> hello :<|> marketing = client api

If our api type instead looked like:

type API = QueryParam "test" Int :> (
    "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
      :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
      :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email)

which is identical to the original api but with an additional "test" query parameter for all endpoints, how would we obtain our client functions? I have tried several variants of pattern matching, but to no avail.

If all else, fails, the "test" query parameter could be repeated in the api type for each endpoint, but this is Haskell, we try to avoid repetition.

4

1 回答 1

4

仆人 API 定义存在于类型级别。如果我们想操作它们,我们需要一个函数之类的东西,它将类型(不是值,类型本身)转换为其他类型。

Haskell 中最接近这种类型级函数的东西称为封闭类型族

{-# LANGUAGE TypeFamilies #-}

type family PrependParam api where
    PrependParam (a :<|> b) = PrependParam a :<|> PrependParam b
    PrependParam leaf = QueryParam "test" Int :> leaf

type API' = PrependParam API

:<|>分隔路线,同时:>分隔路线中的组件。我们正在映射路由树并为每个路由添加一个前缀。

我们可以使用以下命令检查它是否可以从ghci运行:kind!

ghci> :kind! API'
API' :: *
= (QueryParam "test" Int
   :> ("position"
       :> (Capture "x" Int :> (Capture "y" Int :> Get '[JSON] Position))))
  :<|> ((QueryParam "test" Int
         :> ("hello"
             :> (QueryParam "name" String :> Get '[JSON] HelloMessage)))
        :<|> (QueryParam "test" Int
              :> ("marketing"
                  :> (ReqBody '[JSON] ClientInfo :> Post '[JSON] Email))))
于 2017-05-16T19:55:10.993 回答