Ocaml Yojson列表中Yojson元素的子类型

Ocaml Yojson列表中Yojson元素的子类型,ocaml,Ocaml,我遇到了一个关于子类型的错误。 对于这段代码,List.map(fun((字符串goal\u feat):>Basic.t)->goal\u feat(goal\u feats\u json:>Basic.t List)。 我在vscode中遇到以下错误: This expression cannot be coerced to type Yojson.Basic.t = [ Assoc of (string * Yojson.Basic.t) list | Bool of

我遇到了一个关于子类型的错误。 对于这段代码,
List.map(fun((字符串goal\u feat):>Basic.t)->goal\u feat(goal\u feats\u json:>Basic.t List)
。 我在vscode中遇到以下错误:

This expression cannot be coerced to type
  Yojson.Basic.t =
    [ Assoc of (string * Yojson.Basic.t) list
    | Bool of bool
    | Float of float
    | Int of int
    | List of Yojson.Basic.t list
    | Null
    | String of string ];
it has type [< String of 'a ] -> 'b but is here used with type
  [< Yojson.Basic.t ]. 
无法将此表达式强制为类型
Yojson.Basic.t=
[Assoc of(string*Yojson.Basic.t)列表
|布尔的布尔
|浮子的浮子
|整数的整数
|Yojson.Basic.t列表的列表
|空的
|字符串的字符串];
它具有类型['b,但在这里与类型一起使用
[
编译时,我遇到以下错误。
错误:语法错误:“)”应为


如果我将代码更改为
List.map(fun((字符串goal\u feat):Basic.t)->goal\u feat)(goal\u feats\u json:>Basic.t List)
,它使用q显式类型转换而不是子类型转换,那么错误就消失了。当我使用子类型时,我无法理解我的代码有什么问题。非常感谢任何能给我帮助的人

首先,最有可能的答案是

let to_strings xs =
  List.map (function `String x -> x | _ -> assert false) (xs :> t list)
编译器告诉您,您的函数只处理一种情况,而您正在向它传递一个可能包含许多其他内容的列表,因此可能会出现运行时错误。因此,最好向编译器表明,您知道只需要使用
String
标记的变量。这就是我们在上面的例子中所做的。现在我们的函数具有类型
[>Yojson.Basic.t]

现在回到你的直接问题。它是
(expr:typeexpr)
,但是在
乐趣((String-goal\u-feat):>Basic.t)->goal\u-feat
代码段中,
String-goal\u-feat
是一种模式,您不能强制模式,因此我们将在这里使用它来赋予它正确的、更一般的类型1,例如

这将告诉编译器,函数的参数应属于更广泛的类型,并立即将错误转化为警告8

Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(`Bool _|`Null|`Assoc _|`List _|`Float _|`Int _)
这就是我在文章的第一部分所说的。让警告8无人值守通常是个坏主意,因此我建议您使用第一种解决方案,或者,找到一种方法向编译器证明您的列表没有任何其他变体,例如,您可以使用
list.filter\u map

let collect_strings : t list -> [`String of string] list = fun xs ->
  List.filter_map (function
      | `String s -> Some (`String s)
      | _ -> None) xs
一个更自然的解决方案是返回未标记的字符串(除非您确实需要标记,例如,当您需要将此列表传递给一个在
[>t]
上多态的函数时)(此外,我正在使用
t
for
Yojson.Basic.t
来缩短文章,但您应该在代码中使用正确的名称)。因此,这里有一个解决方案,它将提取字符串并使每个人都满意(它将与其他标记一起丢弃值)

请注意,此处不需要类型注释,我们可以轻松删除它们以获得最通用的多义类型:

let collect_strings xs =
  List.filter_map (function
      | `String s -> Some s
      | _ -> None) xs
它将得到类型

[> `String a] list -> 'a list
这意味着,带有任何标记的多态变体列表,返回带有
字符串
标记的对象列表


1) 强制对模式不起作用并不是一个限制,而且强制模式也没有任何意义。强制接受具有现有类型的表达式,并将其向上转换(减弱)为超类型。函数参数不是表达式,因此这里没有强制的内容。您可以使用类型对其进行注释,例如,
fun(x:#t)->x
会说我们的函数需要类型
[
的值,这比未注释的类型
'a
更不一般。总而言之,当您有一个函数接受一个具有对象或多态变量类型的值,并且在某些表达式中希望将其与弱化(上置类型)一起使用时,需要强制

type a = [`A]
type b = [`B]
type t = [a | b]

let f : t -> unit = fun _ -> ()
let example : a -> unit = fun x -> f (x :> t)
这里我们有类型
t
,有两个子类型
a
b
。我们的函数
f
接受基本类型
t
,但是
示例
特定于
a
。为了能够在类型为
a
的对象上使用
f
,我们需要显式的类型强制来削弱(我们在这里丢失类型信息)其类型为
t
。请注意,我们不会更改
x
本身的类型,因此下面的示例仍然会检查类型:

let rec example : a -> unit = fun x -> f (x :> t); example x
也就是说,我们将参数的类型减弱为
f
,但是变量
x
仍然具有更强的类型
a
,因此我们仍然可以将其用作
a
类型的值

type a = [`A]
type b = [`B]
type t = [a | b]

let f : t -> unit = fun _ -> ()
let example : a -> unit = fun x -> f (x :> t)
let rec example : a -> unit = fun x -> f (x :> t); example x