在 OCaml 中漂亮地打印一个 Hashtbl 以使用 ppx 派生
Pretty-print a Hashtbl in OCaml to work with ppx-deriving
我正在尝试使用 ppx 派生在 OCaml 中漂亮地打印包含哈希表(使用 Base 标准库)的自定义记录类型,但我需要实现 Hashtbl.pp 才能正常工作。
我已经尝试查看在线示例,我找到的最好的示例是 https://github.com/ocaml-ppx/ppx_deriving#testing-plugins,但我仍然遇到奇怪的类型错误,例如 "This function has type Formatter.t -> (string, Value.t) Base.Hashtbl.t -> unit. It is applied to too many arguments; maybe you forgot a `;'"
如何使用 pp
函数扩展 Hashtbl 模块?
到目前为止,这是我的代码(Value.t 是我用 [@@deriving show] 成功注释的自定义类型:
open Base
(* Extend Hashtbl with a custom pretty-printer *)
module Hashtbl = struct
include Hashtbl
let rec (pp : Formatter.t -> (string, Value.t) Hashtbl.t -> Ppx_deriving_runtime.unit) =
fun fmt -> function
| ht ->
List.iter
~f:(fun (str, value) ->
Caml.Format.fprintf fmt "@[<1>%s: %s@]@." str (Value.string_of value))
(Hashtbl.to_alist ht)
and show : (string, Value.t) Hashtbl.t -> Ppx_deriving_runtime.string =
fun s -> Caml.Format.asprintf "%a" pp s
;;
end
type t =
{ values : (string, Value.t) Hashtbl.t
; enclosing : t option
}
[@@deriving show]
解决方案 1
您记录的 values
字段的类型是参数化的,具有两个类型变量,因此派生程序正在尝试使用由键和数据漂亮地参数化的通用 pp
函数-打印机,例如,以下将为任何散列table启用show
(具有任何键和任何值,只要键和值是可显示的,
module Hashtbl = struct
include Base.Hashtbl
let pp pp_key pp_value ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%a: %a@]@." pp_key key pp_value data)
end
所以你终于可以定义你的类型了
type t = {
values : (string,Value.t) Hashtbl.t;
enclosing : t option;
} [@@deriving show]
方案二(推荐)
但是,我会建议另一种方法,而不是创建一个通用的 Hashtable 模块,而是创建一个专门的 Values
模块,例如,
module Values = struct
type t = (string, Value.t) Hashtbl.t
let pp ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%s: %s@]@." key (Value.to_string data))
end
现在您可以将其用作,
type t = {
values : Values.t;
enclosing : t option;
} [@@deriving show]
解决方案 3
如果你仍然想要一个通用的 printable 哈希 table,那么我建议不要使用 include
语句,而是只实现所需的 printable ('k,'s) Hashtbl.t
类型的接口,例如
module Hashtbl_printable = struct
type ('k,'s) t = ('k, 's) Hashtbl.t
let pp pp_key pp_value ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%a: %a@]@." pp_key key pp_value data)
end
type t = {
values : (string, Value.t) Hashtbl_printable.t;
enclosing : t option;
} [@@deriving show]
我正在尝试使用 ppx 派生在 OCaml 中漂亮地打印包含哈希表(使用 Base 标准库)的自定义记录类型,但我需要实现 Hashtbl.pp 才能正常工作。
我已经尝试查看在线示例,我找到的最好的示例是 https://github.com/ocaml-ppx/ppx_deriving#testing-plugins,但我仍然遇到奇怪的类型错误,例如 "This function has type Formatter.t -> (string, Value.t) Base.Hashtbl.t -> unit. It is applied to too many arguments; maybe you forgot a `;'"
如何使用 pp
函数扩展 Hashtbl 模块?
到目前为止,这是我的代码(Value.t 是我用 [@@deriving show] 成功注释的自定义类型:
open Base
(* Extend Hashtbl with a custom pretty-printer *)
module Hashtbl = struct
include Hashtbl
let rec (pp : Formatter.t -> (string, Value.t) Hashtbl.t -> Ppx_deriving_runtime.unit) =
fun fmt -> function
| ht ->
List.iter
~f:(fun (str, value) ->
Caml.Format.fprintf fmt "@[<1>%s: %s@]@." str (Value.string_of value))
(Hashtbl.to_alist ht)
and show : (string, Value.t) Hashtbl.t -> Ppx_deriving_runtime.string =
fun s -> Caml.Format.asprintf "%a" pp s
;;
end
type t =
{ values : (string, Value.t) Hashtbl.t
; enclosing : t option
}
[@@deriving show]
解决方案 1
您记录的 values
字段的类型是参数化的,具有两个类型变量,因此派生程序正在尝试使用由键和数据漂亮地参数化的通用 pp
函数-打印机,例如,以下将为任何散列table启用show
(具有任何键和任何值,只要键和值是可显示的,
module Hashtbl = struct
include Base.Hashtbl
let pp pp_key pp_value ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%a: %a@]@." pp_key key pp_value data)
end
所以你终于可以定义你的类型了
type t = {
values : (string,Value.t) Hashtbl.t;
enclosing : t option;
} [@@deriving show]
方案二(推荐)
但是,我会建议另一种方法,而不是创建一个通用的 Hashtable 模块,而是创建一个专门的 Values
模块,例如,
module Values = struct
type t = (string, Value.t) Hashtbl.t
let pp ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%s: %s@]@." key (Value.to_string data))
end
现在您可以将其用作,
type t = {
values : Values.t;
enclosing : t option;
} [@@deriving show]
解决方案 3
如果你仍然想要一个通用的 printable 哈希 table,那么我建议不要使用 include
语句,而是只实现所需的 printable ('k,'s) Hashtbl.t
类型的接口,例如
module Hashtbl_printable = struct
type ('k,'s) t = ('k, 's) Hashtbl.t
let pp pp_key pp_value ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%a: %a@]@." pp_key key pp_value data)
end
type t = {
values : (string, Value.t) Hashtbl_printable.t;
enclosing : t option;
} [@@deriving show]