OCaml中如何正确实现包含多态集合的可表达数据类型并解决语法报错?
报错的核心原因
- 首先是最关键的概念混淆:你定义的
Set是值层面的variant构造子(用来把列表封装成集合实例),它根本不是类型名,不能出现在of后面的类型位置。你写的string Set、bool Set本质是把值构造子当成了类型用,完全不符合OCaml的类型语法规则。而且OCaml的中缀类型写法(比如int list)是仅给内置list类型开放的特殊语法,自定义类型默认不支持这种写法,就算要实现中缀集合语法,也得用合法的类型标识符当类型名,不能拿值构造子凑。 - 其次是语法解析的回溯偏差:解析器遇到非法的类型表达式时,会回溯把报错位置标记在前一个分支结束的
|处,这就是为什么你看到错误定位在EmptySet of Empty后面的竖线上,并不是这个竖线本身有语法问题。 - 最后是设计冗余:你单独定义的
EmptySet of Empty分支完全没有存在的必要——原有的'a set_类型本身就包含Empty构造子,不管哪种元素类型的空集合,都是对应集合类型的一个实例,已经被各个集合分支覆盖了。
正确的实现方式
首先要明确:参数化集合的类型名是set_,所有类型位置上引用集合,都必须用xxx set_的前缀写法,绝对不能用xxx Set(那是值构造子的名字)。
贴合你最初拆分集合类型的写法
(* 保留你最初的集合类型定义 *) type 'a set_ = Empty | Set of 'a list type exType = | Int of int | Bool of bool | String of string | IntSet of int set_ | BoolSet of bool set_ | StringSet of string set_
这个写法里,空集合不需要单独开分支:比如空的字符串集合就是StringSet Empty,空的整数集合就是IntSet Empty,全部被现有分支覆盖。
更精简的通用写法
如果不需要严格区分集合的元素类型,只要让exType本身可以嵌套集合,不需要给int、bool、string各写一个集合分支,可以直接复用exType自身做集合的元素类型:
type 'a set_ = Empty | Set of 'a list type exType = | Int of int | Bool of bool | String of string | ExSet of exType set_
这种写法可以支持任意层级的集合嵌套,代码量更少,也不会出现语法问题。
内容的提问来源于stack exchange,提问作者Samuele B.
相关产品推荐
相关产品推荐

