如何在OCaml中为函数实现约束多态?Yojson类型适配问题
解决Yojson跨子类型的列表提取函数类型兼容问题
你的问题出在模式匹配中的#Yojson.t分支——这个模式会让OCaml将输入的子类型(比如Yojson.Safe.t)自动拓宽为顶层的Yojson.t,导致返回的列表元素类型被固定为单态的Yojson.t,无法保留原输入的子类型约束。
正确实现方式
使用本地抽象类型明确约束类型变量,让OCaml保留输入的子类型信息:
let expect_list : type j. ([< Yojson.t ] as j) -> (j list, exn) result = function | `List js -> Ok js | _ -> Error (Failure "Not a list!")
或者用显式类型注解的写法,效果完全一致:
let expect_list (type j) (json : [< Yojson.t ] as j) : (j list, exn) result = match json with | `List js -> Ok js | _ -> Error (Failure "Not a list!")
原理说明
type j.声明了一个本地抽象类型,告诉OCaml这个函数对所有符合[< Yojson.t ]约束的子类型j都适用,不会将其单态化为顶层的Yojson.t。- 替换
#Yojson.t为_,避免触发类型拓宽——#Yojson.t是开放多态变体模式,会匹配所有属于Yojson.t的构造器,同时强制类型统一为Yojson.t;而_仅匹配剩余所有情况,不会改变原有类型约束。
修改后,当传入Yojson.Safe.t、Yojson.Basic.t等子类型的JSON时,函数返回的Ok分支会自动约束为对应子类型的列表,完美兼容Yojson的所有子类型。
内容的提问来源于stack exchange,提问作者Sventimir
相关产品推荐
相关产品推荐

