如何为OCaml的Map映射类型预先指定值类型
问题原因
你写的with type key = string and 'a = int不符合语法,核心原因是:
Map.S中的type !+'a t是带一个类型参数的类型构造器,'a是这个构造器的类型参数,不是模块内定义的具名类型with type约束的左侧必须是模块内定义的具名类型(可带参数),不能直接给类型变量赋值- 普通
with type要求等式两边类型的参数数量一致,无法直接把带参数的类型构造器固定为无参数的具体类型。
实现方法
通用简便方案:类型别名
90%以上的场景不需要专门定义固定值类型的模块签名,直接给实例化后的Map类型起别名即可,编译器会自动做类型检查,禁止存入错误类型的值:
(* 构造键为string的基础Map模块 *) module StringMap = Map.Make(String) (* 定义固定值为int的Map类型 *) type string_int_map = int StringMap.t
使用时无需额外标注,类型错误会被编译器直接捕获:
(* 合法,自动推断为string_int_map类型 *) let valid_map = StringMap.add "id" 100 StringMap.empty (* 编译报错,值类型为string和要求的int不匹配 *) let invalid_map = StringMap.add "id" "100" StringMap.empty
强模块约束方案:破坏性类型替换
如果你需要定义严格的模块签名,强制符合该签名的Map只能存储指定类型的值,用破坏性类型替换(:=语法)移除原签名中参数化的t定义,替换为固定值类型的具体类型即可:
module StringMap = Map.Make(String) module type StringIntMap = sig (* 引入Map.S签名,固定key为string,删除原参数化的'a t定义 *) include Map.S with type key = string and type 'a t := int StringMap.t (* 声明固定值类型的非参数化t *) type t = int StringMap.t end
替换后该签名内的所有函数会自动固定值类型为int,比如add函数的签名会从原来的val add: key -> 'a -> 'a t -> 'a t变为val add: key -> int -> t -> t,完全满足预先固定值类型的要求。
内容的提问来源于stack exchange,提问作者Max Heiber
相关产品推荐
相关产品推荐

