在 OCaml 中为 Hash Table 定义类型别名
Defining a type alias for Hash Table in OCaml
我正在尝试使用 atdgen,它要求您定义要转换为 JSON 的 OCaml 对象的类型,它称之为 "atd file"
因此对于 Hashtbl.t atdgen 生成的代码如下所示:
type ('a, 'b) bucketlist =
| Empty
| Cons of 'a * 'b * ('a, 'b) bucketlist
type ('a, 'b) tbl = ('a, 'b) Hashtbl.t = {
mutable size: int;
mutable data: ('a, 'b) bucketlist array;
mutable seed: int;
initial_size: int;
}
编译器抛出一个:
错误:此变体或记录定义与
输入 ('a, 'b) Hashtbl.t。他们的种类不同。
而且我不知道如何以 atdgen 生成代码的方式定义别名来帮助我将 Hashtbl 序列化为 JSON。因为我在 stdlib/Hashtbl.ml 中进行了验证并且类型 defs 看起来很像。
我来了 ,看起来它可以帮助我,但我无法弄清楚建议的内容与 atdgen 生成的内容有什么不同。
这是我的 atd def 的样子:
type ('a, 'b) bucketlist = [
| Empty
| Cons of ('a * 'b * ('a, 'b) bucketlist)
] <ocaml repr="classic">
type ('a, 'b) tbl <ocaml predef module="Hashtbl" t="t"> = {
size <ocaml mutable>: int;
data <ocaml mutable>: ('a, 'b) bucketlist list <ocaml repr="array">;
seed <ocaml mutable>: int;
initial_size: int;
}
我对atdgen一无所知,但在我看来Hashtbl.t是一个抽象类型。您不能将其定义为与具体记录类型相同的类型。这可能就是编译器说种类不同时的意思。
# module A : sig type 'a t end =
struct type 'a t = { l : 'a list } end;;
module A : sig type 'a t end
# type 'a myt = 'a A.t = { l : 'a list };;
Error: This variant or record definition does not match that of type 'a A.t
Their kinds differ.
(换句话说,你不能将散列 table 的内部结构打包成 JSON 而不违反 Hashtbl 模块的抽象层。)
如果散列 table 的键是字符串或可能是整数,我建议坚持使用 JSON 对象和 OCaml 端的 use a wrapper。
如果您需要支持任意类型的键,您可能应该使用包含 2 个元素的数组,因为 JSON 没有更好的选择。
这是说明这两种情况的完整示例:
文件table.atd
:
(*
If the keys of the hash table are strings (or maybe ints),
use the standard JSON representation as an object:
*)
type 'v table_as_object =
(string * 'v) list <json repr="object">
wrap <ocaml t="(string, 'v) Table.t"
module="Table">
(*
If you need to support keys of arbitrary types,
you probably should use an array of arrays of 2 elements because JSON
doesn't offer anything better:
*)
type ('k, 'v) table_as_array =
('k * 'v) list
wrap <ocaml t="('k, 'v) Table.t"
module="Table">
type stuff = {
x: int;
}
type table_ar = (string, stuff) table_as_array
type table_obj = stuff table_as_object
文件table.ml
:
type ('k, 'v) t = ('k, 'v) Hashtbl.t
let of_list l =
let tbl = Hashtbl.create (2 * List.length l) in
List.iter (fun (k, v) -> Hashtbl.add tbl k v) l;
tbl
let to_list tbl =
Hashtbl.fold (fun k v l -> (k, v) :: l) tbl []
let wrap = of_list
let unwrap = to_list
文件test_table.ml
:
open Table_t
let main () =
let tbl = Hashtbl.create 10 in
Hashtbl.add tbl "abc" { x = 123 };
Hashtbl.add tbl "def" { x = 456 };
let json_ar = Table_j.string_of_table_ar tbl in
let json_obj = Table_j.string_of_table_obj tbl in
print_endline (Yojson.Basic.prettify json_ar);
print_endline (Yojson.Basic.prettify json_obj)
let () = main ()
构建命令:
atdgen -t table.atd
atdgen -j -j-std table.atd
ocamlfind ocamlopt -o test_table \
table.ml table_t.mli table_t.ml table_j.mli table_j.ml test_table.ml \
-package atdgen -linkpkg
输出:
$ ./test_table
[ [ "abc", { "x": 123 } ], [ "def", { "x": 456 } ] ]
{ "abc": { "x": 123 }, "def": { "x": 456 } }
我正在尝试使用 atdgen,它要求您定义要转换为 JSON 的 OCaml 对象的类型,它称之为 "atd file"
因此对于 Hashtbl.t atdgen 生成的代码如下所示:
type ('a, 'b) bucketlist =
| Empty
| Cons of 'a * 'b * ('a, 'b) bucketlist
type ('a, 'b) tbl = ('a, 'b) Hashtbl.t = {
mutable size: int;
mutable data: ('a, 'b) bucketlist array;
mutable seed: int;
initial_size: int;
}
编译器抛出一个:
错误:此变体或记录定义与 输入 ('a, 'b) Hashtbl.t。他们的种类不同。
而且我不知道如何以 atdgen 生成代码的方式定义别名来帮助我将 Hashtbl 序列化为 JSON。因为我在 stdlib/Hashtbl.ml 中进行了验证并且类型 defs 看起来很像。
我来了
这是我的 atd def 的样子:
type ('a, 'b) bucketlist = [
| Empty
| Cons of ('a * 'b * ('a, 'b) bucketlist)
] <ocaml repr="classic">
type ('a, 'b) tbl <ocaml predef module="Hashtbl" t="t"> = {
size <ocaml mutable>: int;
data <ocaml mutable>: ('a, 'b) bucketlist list <ocaml repr="array">;
seed <ocaml mutable>: int;
initial_size: int;
}
我对atdgen一无所知,但在我看来Hashtbl.t是一个抽象类型。您不能将其定义为与具体记录类型相同的类型。这可能就是编译器说种类不同时的意思。
# module A : sig type 'a t end =
struct type 'a t = { l : 'a list } end;;
module A : sig type 'a t end
# type 'a myt = 'a A.t = { l : 'a list };;
Error: This variant or record definition does not match that of type 'a A.t
Their kinds differ.
(换句话说,你不能将散列 table 的内部结构打包成 JSON 而不违反 Hashtbl 模块的抽象层。)
如果散列 table 的键是字符串或可能是整数,我建议坚持使用 JSON 对象和 OCaml 端的 use a wrapper。
如果您需要支持任意类型的键,您可能应该使用包含 2 个元素的数组,因为 JSON 没有更好的选择。
这是说明这两种情况的完整示例:
文件table.atd
:
(*
If the keys of the hash table are strings (or maybe ints),
use the standard JSON representation as an object:
*)
type 'v table_as_object =
(string * 'v) list <json repr="object">
wrap <ocaml t="(string, 'v) Table.t"
module="Table">
(*
If you need to support keys of arbitrary types,
you probably should use an array of arrays of 2 elements because JSON
doesn't offer anything better:
*)
type ('k, 'v) table_as_array =
('k * 'v) list
wrap <ocaml t="('k, 'v) Table.t"
module="Table">
type stuff = {
x: int;
}
type table_ar = (string, stuff) table_as_array
type table_obj = stuff table_as_object
文件table.ml
:
type ('k, 'v) t = ('k, 'v) Hashtbl.t
let of_list l =
let tbl = Hashtbl.create (2 * List.length l) in
List.iter (fun (k, v) -> Hashtbl.add tbl k v) l;
tbl
let to_list tbl =
Hashtbl.fold (fun k v l -> (k, v) :: l) tbl []
let wrap = of_list
let unwrap = to_list
文件test_table.ml
:
open Table_t
let main () =
let tbl = Hashtbl.create 10 in
Hashtbl.add tbl "abc" { x = 123 };
Hashtbl.add tbl "def" { x = 456 };
let json_ar = Table_j.string_of_table_ar tbl in
let json_obj = Table_j.string_of_table_obj tbl in
print_endline (Yojson.Basic.prettify json_ar);
print_endline (Yojson.Basic.prettify json_obj)
let () = main ()
构建命令:
atdgen -t table.atd
atdgen -j -j-std table.atd
ocamlfind ocamlopt -o test_table \
table.ml table_t.mli table_t.ml table_j.mli table_j.ml test_table.ml \
-package atdgen -linkpkg
输出:
$ ./test_table
[ [ "abc", { "x": 123 } ], [ "def", { "x": 456 } ] ]
{ "abc": { "x": 123 }, "def": { "x": 456 } }