Pattern matching 用GADT建模语法,但类型参数赢了';不统一

Pattern matching 用GADT建模语法,但类型参数赢了';不统一,pattern-matching,ocaml,gadt,polymorphic-variants,Pattern Matching,Ocaml,Gadt,Polymorphic Variants,我认为我已经找到了一种使用GADT对语法建模的好方法,通过给每个构造函数(例如,Char)一个返回类型参数,该参数是多态变量(例如,[`Char]t),然后使用多态变量统一特性来限制接下来允许哪些构造函数(例如,[您只需要使用本地抽象类型,就可以为每个分支细化类型: let rec to_list:type a.a t->string list=函数 |打开rest->“(”::列出rest |减rest->“-”::列出rest |Char rest->“a”::列出rest |关闭->[“”

我认为我已经找到了一种使用GADT对语法建模的好方法,通过给每个构造函数(例如,
Char
)一个返回类型参数,该参数是多态变量(例如,
[`Char]t
),然后使用多态变量统一特性来限制接下来允许哪些构造函数(例如,
[您只需要使用本地抽象类型,就可以为每个分支细化类型:

let rec to_list:type a.a t->string list=函数
|打开rest->“(”::列出rest
|减rest->“-”::列出rest
|Char rest->“a”::列出rest
|关闭->[“”]
为了说明原因,@octachron在今天早些时候的一个类似问题上写道

编辑:

若要将此函数限制为案例的子集,我认为您必须应用两种不同的类型签名。一种外部签名用于多态变量,另一种内部签名用于局部抽象类型。然而,由于函数是递归的,我们在递归时也需要局部抽象类型是外部的。否则,我们可以刚刚注释了模式匹配的值

我可以想出几种方法来做到这一点:

选项1,将其包装在模块中(或将外部签名放入.mli中):

模块M:sig
val to_列表:[字符串列表]
end=struct
let rec to_list:type a.a t->string list=函数
|打开rest->“(”::列出rest
|减rest->“-”::列出rest
|Char rest->“a”::列出rest
|关闭->[“”]
结束
选项2,使用本地定义的函数将“内部”签名置于:

let to_list:[字符串列表=
let rec aux:type a.a t->string list=函数
|打开rest->“(”::辅助rest
|负rest->“-”::辅助rest
|字符rest->“a”::辅助rest
|关闭->[“”]
在里面
辅助的

这是很有帮助的。但是,在这个问题上稍微扩展一下,您将如何编写一个函数来接受案例的子集,例如,
to_list:[<`减号|`Char | `Close]t->string list
?我觉得很尴尬。请看更新后的答案。如果有更优雅的方式,我不知道,但我认为这是一个非常有趣的场景。可能值得将此作为一个单独的问题发布,或者在这个问题上提供奖励,以获得更多关注。
(* Grammar ::= Open (Minus? Char)+ Close *)

type _ t =
  | Open:  [<`Minus | `Char] t -> [`Open] t
  | Minus: [<`Char] t -> [`Minus] t
  | Char:  [<`Minus | `Char | `Close] t -> [`Char] t
  | Close: [`Close] t
let example =
  Open (Minus (Char (Char (Minus (Char (Close))))))

(* let counter_example =
  Open (Minus (Char (Minus (Minus (Char (Close)))))) *)
let rec to_list = function
  | Open rest -> "(" :: to_list rest
  | Minus rest -> "-" :: to_list rest
  | Char rest -> "a" :: to_list rest
  | Close -> [")"]
File "./tmp.ml", line 21, characters 4-14:
21 |   | Minus rest -> "-" :: to_list rest
         ^^^^^^^^^^
Error: This pattern matches values of type [ `Minus ] t
       but a pattern was expected which matches values of type [ `Open ] t
       Type [ `Minus ] is not compatible with type [ `Open ]