在 yojson 列表中对 Yojson 元素进行子类型化
Subtyping for Yojson element in a yojson list
我遇到了关于子类型的错误。
对于此代码,List.map (fun ((String goal_feat):> Basic.t) -> goal_feat) (goal_feats_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 ].
编译时遇到如下错误。
Error: Syntax error: ')' expected
.
如果我将代码更改为 List.map (fun ((String goal_feat): Basic.t) -> goal_feat) (goal_feats_json:> Basic.t list)
,使用显式类型转换而不是子类型,则错误消失。当我使用子类型化时,我不明白我的代码有什么问题。非常感谢任何能给我一些帮助的人。
首先,您正在寻找的答案很可能是
let to_strings xs =
List.map (function `String x -> x | _ -> assert false) (xs :> t list)
编译器告诉您您的函数只处理一种情况,而您传递给它的列表可能包含许多其他内容,因此可能会出现运行时错误。因此,最好向编译器表明您知道只有标记为 String
的变体是预期的。这就是我们在上面的例子中所做的。现在我们的函数的类型是 [> Yojson.Basic.t]
.
现在回到你的直接问题。这里的syntax for coercion is (expr : typeexpr)
, however in the fun ((String goal_feat):> Basic.t) -> goal_feat
snippet, String goal_feat
is a pattern, and you cannot coerce a pattern, so we shall use parenthesized pattern是为了给它赋予正确的,更笼统的,类型1,例如,
let exp xs =
List.map (fun (`String x : t) -> x ) (xs :> t list)
这会告诉编译器你的函数的参数应该属于更宽的类型,并立即将错误转为警告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 _)
这就是我在 post 的第一部分所说的内容。让警告 8 无人看管通常是一个坏主意,所以我建议您使用第一个解决方案,或者,找到一种方法向编译器证明您的列表没有任何其他变体,例如,您可以为此使用 List.filter_map
:
let collect_strings : t list -> [`String of string] list = fun xs ->
List.filter_map (function
| `String s -> Some (`String s)
| _ -> None) xs
更自然的解决方案是 return 未标记的字符串(除非你真的需要标记,例如,当你需要将此列表传递给在 [=25= 上具有多态性的函数时](此外,我使用 t
代替 Yojson.Basic.t
来缩短 post,但您应该在代码中使用正确的名称)。所以这里是提取字符串和让每个人都开心(它会丢弃其他标签的值),
let collect_strings : t list -> string list = fun xs ->
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
注意,这里不需要类型注解,我们可以轻松去掉它们,得到最通用的多态类型:
let collect_strings xs =
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
它将获得类型
[> `String a] list -> 'a list
这意味着,带有任何标签的多态变体列表,returning 带有 String
标签的对象列表。
1)强制转换对模式不起作用并不是限制,而且强制转换模式没有任何意义。强制转换采用具有现有类型的表达式并将其向上转换(弱化)为超类型。函数参数不是表达式,所以这里没有什么可以强制的。你可以只用类型注释它,例如,fun (x : #t) -> x
会说我们的函数需要类型 [< t]
的值,这比未注释的类型 '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
,但 example
特定于 a
。为了能够在类型为 a
的对象上使用 f
,我们需要一个显式类型强制将其类型弱化(我们在这里丢失了类型信息)为 t
。请注意,我们并没有改变 x
本身的类型,所以下面的例子仍然是类型检查:
let rec example : a -> unit = fun x -> f (x :> t); example x
即,我们弱化了 f
的参数类型,但变量 x
仍然具有更强的类型 a
,所以我们仍然可以将它用作输入 a
。
我遇到了关于子类型的错误。
对于此代码,List.map (fun ((String goal_feat):> Basic.t) -> goal_feat) (goal_feats_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 ].
编译时遇到如下错误。
Error: Syntax error: ')' expected
.
如果我将代码更改为 List.map (fun ((String goal_feat): Basic.t) -> goal_feat) (goal_feats_json:> Basic.t list)
,使用显式类型转换而不是子类型,则错误消失。当我使用子类型化时,我不明白我的代码有什么问题。非常感谢任何能给我一些帮助的人。
首先,您正在寻找的答案很可能是
let to_strings xs =
List.map (function `String x -> x | _ -> assert false) (xs :> t list)
编译器告诉您您的函数只处理一种情况,而您传递给它的列表可能包含许多其他内容,因此可能会出现运行时错误。因此,最好向编译器表明您知道只有标记为 String
的变体是预期的。这就是我们在上面的例子中所做的。现在我们的函数的类型是 [> Yojson.Basic.t]
.
现在回到你的直接问题。这里的syntax for coercion is (expr : typeexpr)
, however in the fun ((String goal_feat):> Basic.t) -> goal_feat
snippet, String goal_feat
is a pattern, and you cannot coerce a pattern, so we shall use parenthesized pattern是为了给它赋予正确的,更笼统的,类型1,例如,
let exp xs =
List.map (fun (`String x : t) -> x ) (xs :> t list)
这会告诉编译器你的函数的参数应该属于更宽的类型,并立即将错误转为警告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 _)
这就是我在 post 的第一部分所说的内容。让警告 8 无人看管通常是一个坏主意,所以我建议您使用第一个解决方案,或者,找到一种方法向编译器证明您的列表没有任何其他变体,例如,您可以为此使用 List.filter_map
:
let collect_strings : t list -> [`String of string] list = fun xs ->
List.filter_map (function
| `String s -> Some (`String s)
| _ -> None) xs
更自然的解决方案是 return 未标记的字符串(除非你真的需要标记,例如,当你需要将此列表传递给在 [=25= 上具有多态性的函数时](此外,我使用 t
代替 Yojson.Basic.t
来缩短 post,但您应该在代码中使用正确的名称)。所以这里是提取字符串和让每个人都开心(它会丢弃其他标签的值),
let collect_strings : t list -> string list = fun xs ->
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
注意,这里不需要类型注解,我们可以轻松去掉它们,得到最通用的多态类型:
let collect_strings xs =
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
它将获得类型
[> `String a] list -> 'a list
这意味着,带有任何标签的多态变体列表,returning 带有 String
标签的对象列表。
1)强制转换对模式不起作用并不是限制,而且强制转换模式没有任何意义。强制转换采用具有现有类型的表达式并将其向上转换(弱化)为超类型。函数参数不是表达式,所以这里没有什么可以强制的。你可以只用类型注释它,例如,fun (x : #t) -> x
会说我们的函数需要类型 [< t]
的值,这比未注释的类型 '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
,但 example
特定于 a
。为了能够在类型为 a
的对象上使用 f
,我们需要一个显式类型强制将其类型弱化(我们在这里丢失了类型信息)为 t
。请注意,我们并没有改变 x
本身的类型,所以下面的例子仍然是类型检查:
let rec example : a -> unit = fun x -> f (x :> t); example x
即,我们弱化了 f
的参数类型,但变量 x
仍然具有更强的类型 a
,所以我们仍然可以将它用作输入 a
。