我正在尝试为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
从<abstr>
中获取print b
以外的其他内容。我希望stringify_that_saves_my_ass
在我的自定义打印机中提供(1)的表示,以便于打印地图值。
答案 0 :(得分:0)
要安装在ocamldebug或ocaml toplevel中,打印机需要具有以下签名:
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;;
我希望,这足以说明这一点。
答案 1 :(得分:0)
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
方法的麻烦。