我正在阅读出色的Why is servant a type-level DSL?。我已经到了这一节,到目前为止,实现所存在的问题是Endpoint
中捕获的数量可以变化,并且如果没有依赖类型,就无法实现全部的链接生成功能。
Endpoint
的定义是:
data Method = Get | Post
data Endpoint = Static String Endpoint
| Capture Endpoint
| Verb Method
和示例定义为:
getHello :: Endpoint
getHello = Static "hello" (Capture (Verb Get))
twoCaptures :: Endpoint
twoCaptures = Capture (Capture (Verb Post))
noCaptures :: Endpoint
noCaptures = Static "hello" (Verb Post)
和非总计链接制作功能是:
linkTo :: Endpoint -> [String] -> Link
linkTo (Static str rest) captureValues = str : linkTo rest captureValues
linkTo (Capture rest) (c : cs) = c : linkTo rest cs
linkTo (Capture rest) [] = error "linkTo: capture value needed but the list is empty" -- :-(
linkTo (Verb method) _ = []
我对以下内容感兴趣:
幸运的是,GADT在这里可以提供帮助。我们可以将
Endpoint
变成GADT 跟踪捕获,然后使用一些类型级别的计算来获取 我们的捕获列表中的链接建立函数的类型,例如 以及通过类型类实例定义链接制作功能 这将通过捕获并为每个添加一个参数 它们...基于GADT的方法在非常稳定的域中也可以很好地工作(除了更易于使用),由于我们所要求的灵活性,因此此处不予考虑。
我对尝试使用GADT方法感兴趣,但是我可以对如何创建GADT做一些提示,该方法将“跟踪捕获,然后使用一些类型级别的计算来获取链接的类型-捕获列表中的功能”
任何人都可以给我一些有关如何开始使用GADT版本的提示。谢谢。
答案 0 :(得分:2)
我对Servant不熟悉,但也许引述是指某些GADT,例如以下内容。想法是定义一种类型Endpoint t
,其中t
的格式为String -> String -> ... -> Link
,其中所有字符串参数都对应于捕获。完成此操作后,toLink
的类型就简单为Endpoint t -> t
。
我没有使用类型类。
{-# LANGUAGE GADTs #-}
module ServantEndpoint where
type Link = [String]
data Method = Get | Post
data Endpoint t where
Static :: String -> Endpoint t -> Endpoint t
Capture :: Endpoint t -> Endpoint (String -> t)
Verb :: Method -> Endpoint Link
linkTo :: Endpoint t -> t
linkTo e = go e []
where
go :: Endpoint t -> Link -> t
go (Static str rest) l = go rest (str : l)
go (Capture rest) l = \s -> go rest (s : l)
go (Verb _method) l = reverse l
一个小例子:
test :: Link
test = f "capture1" "capture2"
where f = linkTo (Capture (Static "static1" (Capture (Static "static2" (Verb Get)))))
-- output: ["capture1","static1","capture2","static2"]