2

我正在编写一些 CRUD 助手以获得乐趣和利润,并且我发现自己需要一条空路径或 noop 路径。mempty:>,如果你愿意的话。

这就是我想写的:

type Index model =
  Reassoc (QueryParams model :> Get '[JSON] (Collection model))

type family Reassoc xs where
  Reassoc ((x :> y) :> z) = Reassoc (x :> Reassoc (y :> z))
  Reassoc (x :> y) = x :> y

type family QueryParams model

type instance QueryParams User =
  MakeQueryParams '[ '("organizationId", Int) ]

当然,这一切都建立在这个人身上:

type family MakeQueryParams xs where
  MakeQueryParams ( '(sym, ty) ': xs ) 
    = QueryParam sym ty :> MakeQueryParams xs
  MakeQueryParams '[] 
    = ... :(

是否有空路由组合器?

到目前为止,我已经通过next在这些系列中使用一个参数来解决这个问题,但对于 Servant 来说,它的惯用语要少得多。

type family MakeQueryParams xs next where
    MakeQueryParams '[] next =
        next
    MakeQueryParams ('(sym, ty) ': xs) next =
        QueryParam sym ty :> MakeQueryParams xs next

type Index model = QueryParams model (Get '[JSON] (Collection model))

type family QueryParams model next

type instance QueryParams User next =
    MakeQueryParams '[ '("organizationId", Int) ] next
4

1 回答 1

0

如果你真的坚持写作

type API = QueryParams '[ '("id", Int) ] :> Get '[JSON] Bool

您将您foldr喜欢的想法/解决方案(完全没问题)与一个新的组合器结合起来:

data QueryParams (ps :: [(Symbol, *)])

instance HasServer api ctx
  => HasServer (QueryParams '[] :> api) ctx where
    type ServerT (QueryParams '[] api) m = ServerT api m

    route = ...

instance HasServer (QueryParam sym ty :> MakeQueryParams ('(sym, ty) ': ps) api) ctx
  => HasServer (QueryParams ('(sym, ty) ': ps) api) ctx where
    type ServerT (QueryParams ('(sym, ty) ': ps) api) m = ...

    route = ...

为 nil 和 cons 编写单独的实例将使实例的实现更加直接。

可以认为我们必须引入新的组合子,否则我们无法将类型族插入正确的位置。有点像我们有时需要写newtypes 来写不同的实例。

于 2019-02-26T17:40:37.420 回答