在 ocamldebug 自定义打印机中打印枚举类型和记录类型
Printing enumerated and record types within an ocamldebug custom printer
我正在尝试为 Map
类型创建自定义打印机,以便在 ocamldebug
中使用。我想在我的自定义打印机中将调试器的漂亮打印机用于枚举和记录类型。这可能吗?
我有一个模块,m.mli
,有几个类型,我正在将整数映射到 gammas:
type alpha = A | B
type gamma = { m: alpha }
module IMap : Map.S with type key = int
val print_map: gamma IMap.t -> unit
实现看起来像这样:
open Format
type alpha = A | B
type gamma = { m: alpha }
module IMap = Map.Make(struct
type t = int
let compare = (-)
end)
let rec ig_pairs = function
| [] -> ()
| [(k,g)] ->
open_hvbox 0;
printf "%u->" k;
print_break 0 2;
print_string (stringifier_that_saves_my_ass g);
close_box ()
| (k,g)::xs ->
open_hvbox 0;
printf "%u->" k;
print_break 0 2;
print_string (stringifier_that_saves_my_ass g);
print_string ",";
close_box ();
ig_pairs xs;
()
let print_map m =
print_string "{";
open_hvbox 0;
ig_pairs (IMap.bindings m);
close_box ();
print_string "}"
最后,我有 script.ml
:
open M
let key = 2
let some_gamma_value = { m = B }
let old = IMap.empty
let b = IMap.add key some_gamma_value old
使用 ocamldebug
单步执行我的脚本(在存根 stringifier_that_saves_my_ass
之后),
- 我可以
print some_gamma_value
获得 some_gamma_value
和 的一个很好的表示
- 我可以
load_printer m.cmo
和 install_printer print_map
从 print b
中得到 <abstr>
以外的东西。
我希望 stringify_that_saves_my_ass
在我的自定义打印机中提供来自 (1) 的表示,以便于打印地图值。
要安装在 ocamldebug 或 ocaml 顶层,打印机需要具有以下签名:
Format.formatter -> t -> unit
其中 t
是您要打印的类型。
这意味着,您的打印机还应该接受一个参数,即格式化程序,即通道的抽象。也就是说,不是只输出到标准输出,而是需要输出到指定的通道。这意味着,您需要使用 fprintf
和 pp_
接受格式化程序的函数系列。
关于 stringifier
问题,因为你的映射在值类型上是多态的,你需要让你的打印机成为一个函数,从打印你的值类型的打印机到打印整个地图。这只是意味着,您需要向打印机添加一个额外的参数,即 pp_value
,它将打印值类型。
为了在一个完整的示例中演示这一点,请查看此 Trie(我忘记从中删除调试代码)模块,
let rec pp pp_val fmt t =
let pp_some_data fmt = function
| None -> ()
| Some v -> fprintf fmt "data =@ %a@," pp_val v in
let pp_table fmt cs =
Tokens.iter cs (fun ~key ~data ->
let toks = Key.sexp_of_token key in
fprintf fmt "@[%a ->@ %a@]"
Sexp.pp toks (pp pp_val) data) in
fprintf fmt "{@;@[%a@ %a@]}@;"
pp_some_data t.data pp_table t.subs
尝试是稍微复杂一点的地图,所以打印机反映了这一点,但让我们来看看打印机的用法。但是在我们需要将 Trie
具体化为特定的键类型之前,让它成为 string
:
module String = Make(struct
type t = string
type token = char with bin_io, compare, sexp
let length = String.length
let nth_token = String.unsafe_get
let token_hash = Char.to_int
end)
现在打印出来。同样,我们只能打印具体结构,所以假设我们要使用 int Trie
,即我们的值类型是 int
。我们为 int
次尝试创建了一台打印机,并安装了它
let pp_int_trie = pp pp_print_int
#install_printer pp_int_trie;;
之后,将打印所有具有 int 值类型的字符串尝试,完整示例如下:
open String
let pp_int_trie = pp pp_print_int
let t = create ();;
add t "hell is my life" 1;;
add t "hello" 2;;
add t "hello my darling Clementine" 3;;
#install_printer pp_int_trie;;
t;;
我希望这足以理解这个想法。
Deriving 库提供预处理器,可以自动为记录和变体类型构建格式化程序。您只需为类型添加后缀 with show
(或 deriving (Show)
)。生成的格式化程序要求任何包含的类型也都带有 with show
后缀。给定 type a = A | B with show
,预处理器生成 module Show_a = ...
使得 Show_a.format: Format.formatter -> t -> unit
。这个 format
函数可以很好地替代调试器的漂亮打印机。
您可以 with show
-后缀 Map
也可以省去编写 print_map
方法的麻烦。
我正在尝试为 Map
类型创建自定义打印机,以便在 ocamldebug
中使用。我想在我的自定义打印机中将调试器的漂亮打印机用于枚举和记录类型。这可能吗?
我有一个模块,m.mli
,有几个类型,我正在将整数映射到 gammas:
type alpha = A | B
type gamma = { m: alpha }
module IMap : Map.S with type key = int
val print_map: gamma IMap.t -> unit
实现看起来像这样:
open Format
type alpha = A | B
type gamma = { m: alpha }
module IMap = Map.Make(struct
type t = int
let compare = (-)
end)
let rec ig_pairs = function
| [] -> ()
| [(k,g)] ->
open_hvbox 0;
printf "%u->" k;
print_break 0 2;
print_string (stringifier_that_saves_my_ass g);
close_box ()
| (k,g)::xs ->
open_hvbox 0;
printf "%u->" k;
print_break 0 2;
print_string (stringifier_that_saves_my_ass g);
print_string ",";
close_box ();
ig_pairs xs;
()
let print_map m =
print_string "{";
open_hvbox 0;
ig_pairs (IMap.bindings m);
close_box ();
print_string "}"
最后,我有 script.ml
:
open M
let key = 2
let some_gamma_value = { m = B }
let old = IMap.empty
let b = IMap.add key some_gamma_value old
使用 ocamldebug
单步执行我的脚本(在存根 stringifier_that_saves_my_ass
之后),
- 我可以
print some_gamma_value
获得some_gamma_value
和 的一个很好的表示
- 我可以
load_printer m.cmo
和install_printer print_map
从print b
中得到<abstr>
以外的东西。
我希望 stringify_that_saves_my_ass
在我的自定义打印机中提供来自 (1) 的表示,以便于打印地图值。
要安装在 ocamldebug 或 ocaml 顶层,打印机需要具有以下签名:
Format.formatter -> t -> unit
其中 t
是您要打印的类型。
这意味着,您的打印机还应该接受一个参数,即格式化程序,即通道的抽象。也就是说,不是只输出到标准输出,而是需要输出到指定的通道。这意味着,您需要使用 fprintf
和 pp_
接受格式化程序的函数系列。
关于 stringifier
问题,因为你的映射在值类型上是多态的,你需要让你的打印机成为一个函数,从打印你的值类型的打印机到打印整个地图。这只是意味着,您需要向打印机添加一个额外的参数,即 pp_value
,它将打印值类型。
为了在一个完整的示例中演示这一点,请查看此 Trie(我忘记从中删除调试代码)模块,
let rec pp pp_val fmt t =
let pp_some_data fmt = function
| None -> ()
| Some v -> fprintf fmt "data =@ %a@," pp_val v in
let pp_table fmt cs =
Tokens.iter cs (fun ~key ~data ->
let toks = Key.sexp_of_token key in
fprintf fmt "@[%a ->@ %a@]"
Sexp.pp toks (pp pp_val) data) in
fprintf fmt "{@;@[%a@ %a@]}@;"
pp_some_data t.data pp_table t.subs
尝试是稍微复杂一点的地图,所以打印机反映了这一点,但让我们来看看打印机的用法。但是在我们需要将 Trie
具体化为特定的键类型之前,让它成为 string
:
module String = Make(struct
type t = string
type token = char with bin_io, compare, sexp
let length = String.length
let nth_token = String.unsafe_get
let token_hash = Char.to_int
end)
现在打印出来。同样,我们只能打印具体结构,所以假设我们要使用 int Trie
,即我们的值类型是 int
。我们为 int
次尝试创建了一台打印机,并安装了它
let pp_int_trie = pp pp_print_int
#install_printer pp_int_trie;;
之后,将打印所有具有 int 值类型的字符串尝试,完整示例如下:
open String
let pp_int_trie = pp pp_print_int
let t = create ();;
add t "hell is my life" 1;;
add t "hello" 2;;
add t "hello my darling Clementine" 3;;
#install_printer pp_int_trie;;
t;;
我希望这足以理解这个想法。
Deriving 库提供预处理器,可以自动为记录和变体类型构建格式化程序。您只需为类型添加后缀 with show
(或 deriving (Show)
)。生成的格式化程序要求任何包含的类型也都带有 with show
后缀。给定 type a = A | B with show
,预处理器生成 module Show_a = ...
使得 Show_a.format: Format.formatter -> t -> unit
。这个 format
函数可以很好地替代调试器的漂亮打印机。
您可以 with show
-后缀 Map
也可以省去编写 print_map
方法的麻烦。