在ocamldebug自定义打印机中打印枚举和记录类型

时间:2015-04-22 05:59:23

标签: ocaml

我正在尝试为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之后),

  1. 我可以print some_gamma_value获得some_gamma_value
  2. 的精彩表示
  3. 我可以load_printer m.cmoinstall_printer print_map<abstr>中获取print b以外的其他内容。
  4. 我希望stringify_that_saves_my_ass在我的自定义打印机中提供(1)的表示,以便于打印地图值。

2 个答案:

答案 0 :(得分:0)

要安装在ocamldebug或ocaml toplevel中,打印机需要具有以下签名:

Format.formatter -> t -> unit

其中t是您要打印的类型。

这意味着,您的打印机还应该接受另一个参数,即格式化程序,即通道的抽象。换句话说,您需要输出到指定的通道,而不是仅输出到标准输出。这意味着,您需要使用接受格式化程序的fprintfpp_系列函数。

关于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方法的麻烦。