servant的公共API中的Data.Proxy(为什么使用ScopedTypeVariables的代理不起作用)

aem*_*xdp 8 haskell types typechecking

我对servant感到很兴奋,只要不妨碍它,我就可以使用它的内部类型魔法,唯一令我困惑的是它在公共API中使用了一个类型代理.这是代码:

serve :: HasServer layout => Proxy layout -> Server layout -> Application
serve p server = toApplication (runRouter (route p (return (RR (Right server)))))
Run Code Online (Sandbox Code Playgroud)

据我所知,类型代理是相当简单的事情,当你没有这种类型的值时需要携带一个类型.那么为什么在Server的类型参数中已有布局类型时传递一个承载布局类型的代理?我已经尝试克隆servant的repo并将代码更改为:

{-# LANGUAGE ScopedTypeVariables #-}

serve :: forall layout . HasServer layout => Server layout -> Application
serve server = toApplication (runRouter (route p (return (RR (Right server)))))
  where
    p :: Proxy layout
    p  = Proxy
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,这无法编译(告诉布局类型不匹配).但是为什么,我的本地p不应该与服务器具有相同的布局类型(打开ScopedTypeVariables)?

Alp*_*ari 9

类型族不是单射的,后面Server就是一个.因此,如果你传递Server MyAPI给这个函数,GHC将无法得出结论layout = MyAPI.不幸的是,我们确实需要一个Proxy.即使我们有内射型家庭,也无济于事:

type API1 = Get '[JSON] User
type API2 = Post '[JSON] User
Run Code Online (Sandbox Code Playgroud)

这两个API是这样的,Server API1 = Server API2API1 /= API2它实际上向我们展示了Server 一定不能是单射的.消除我们想要定位的API类型的最简单方法是Proxy.另一方面,这通常是我们的API在各种服务包中要求的唯一事情.