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
forYojson.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