我正在尝试使用atdgen,它要求您定义您尝试将其转换为JSON的OCaml对象的类型,称为“atd文件”
因此,对于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看似喜欢。
我来across this question,看起来它可以帮助我,但我无法弄清楚建议与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;
}
答案 0 :(得分:4)
如果哈希表的键是字符串或者是整数,我建议坚持使用JAM对象和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 } }
答案 1 :(得分:3)
我对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.
(换句话说,你不能在不违反Hashtbl模块的抽象层的情况下将哈希表的内部结构打包成JSON。)