是否可以定义一个对改进开放的总类型系列?或者,我们可以在类型级别“废弃样板”(还有更多)吗?
我的意思是这是一个类型系列,它具有基本情况
type family F a
type instance F a = a
但允许细化
-- later
type instance F X = Y
这显然是重叠的,并且不允许重复类型系列用于类型安全。然而,这个很好的属性是F
可以应用于任意类型,忽略大多数类型而只是“触发”某些重新索引。
可能没有直接答案。在这种情况下,这是我的用例。或许可能有不同的答案。
我想为Servant创建一个转换API声明的函数。对于那些不熟悉Servant API声明的人来说,它们是一个类似于以下规则构建的类型(但是可以通过新规则扩展)
x is a Symbol |- Seg x is an API (representing a static segment in the URI)
m is a Symbol |- Capture m is an API (capturing data from the URI)
m is a Symbol |- Header m is an API (pulling in header info)
x and y are APIs |- x :<|> y is an API (biased choice)
x and y are APIs |- x :> y is an API (segment concatenation)
m is an HTTP method |- Verb m is an API (endpoint, leaf)
这是一个松散类型的树,可以更具体,但你明白了。
Header "X-API-Version" :> "users" :> Capture "id" :>
( Verb GET
:<|> Verb POST
:<|> Verb DELETE )
我想使用以下规则扩展此API树
|- OptionsStub is an API
ms is a list of Symbols |- Options ms is an API
其中Options ms
是OPTIONS
的端点,它报告CORS头Access-Control-Allowed-Headers
,描述允许在此端点使用的所有请求头的集合。如果一个树中包含一些OptionsStub
个端点,我可以推送Header
我看到的树,并用OptionsStub
类型替换Options
类型。
Header "If-Range" :>
Seg "users" :>
( OptionsStub
:<|> Verb Get
:<|> Capture "id" ( OptionsStub :<|> Verb Get ) )
变为
Header "If-Range" :>
Seg "users" :>
( Options ["If-Range"]
:<|> Verb Get
:<|> Capture "id" ( Options ["If-Range"] :<|> Verb Get ) )
围绕Options
的演示启用本地推理。
type family Push hdrs api
-- interesting rules
type instance Push hdrs OptionsStub = Options hdrs
type instance Push hdrs (a :> b) = a :> Push (Pull a ++ hdrs) b
-- boring, but for completeness
type instance Push hdrs (Verb x) = Verb x
type instance Push hdrs (Seg s) = Seg s
type instance Push hdrs (Capture m) = Capture m
type instance Push hdrs (Header m) = Header m
type instance Push hdrs (x :<|> y) = Push hdrs x :<|> Push hdrs y
type family Pull api :: [*]
type instance Pull (Header m) = '[m]
type instance Pull a = '[] -- OVERLAPPING
至关重要的是,我可以通过对有效API的类型进行完整分析来定义Push
,但我决定不对Pull
执行此操作,因此我遇到了重叠的实例。< / p>
更现实地说,重叠实例是可取的,因为API作为一种开放式扩展(或者实际上,它们是单一的,但在实践中具有相同的效果)而且我的Header
收集系统是固定的。据推测,没有人会用一种表示请求标题的新方式扩展API类型(一种已经存在!)所以我的代码也可以关闭以进行扩展。
但是,如果我使用封闭式系列,那么就像这个问题一样,类型精化将会卡住。
我更喜欢简单地指定我的类型系列
type instance Push hdrs OptionsStub = Options hdrs
type instance Push hdrs (a :> b) = a :> Push (Pull a ++ hdrs) b
type instance Pull (Header m) = '[m]
type instance Pull a = '[]
然后允许用户扩展其API描述规则,而无需扩展这些类型系列的覆盖范围。
有没有任何机制可以实现这种目的?我想要它疯了吗?