OCaml:如何安装漂亮的打印机并在代码中使用它?

OCaml : how to install pretty printer and use it in the code?

在 OCaml 的顶层和调试器中,可以注册一台漂亮的打印机 通过 install_printer printer-name。 有没有办法实现相同的,但在 OCaml 代码中? 更具体地说,我需要一个不需要的日志记录工具 为 log 的每次调用明确指定漂亮的打印机。 也就是说,类似于:

(* First, user sets a global pretty-printer for a type *) 
let pp_foo : Foo -> string = ...
let () = Logging.register pp_foo
...
(* Then it can be used like that *)
let foo : Foo = ...
let () = Logging.log foo

不可能,原因有二:

首先,OCaml 在运行时擦除类型。因此,不可能区分具有相同内存表示的值。例如,[]0None 在编译后具有相同的表示。

其次,log 函数的类型为 'a. 'a -> unit。换句话说,规范说你的函数日志应该适用于过去、现在和未来的任何类型。这只有在您的函数简单地忽略其参数时才有可能,例如:

let f _x = g ()

换句话说,真正的问题可能是你的问题是什么

let () = Logging.log pp_foo foo

?

并不与 Octachron 所说的相矛盾,但实际上可以获得一些转储设施,那就是多态。它会很脆弱,并且确实不会区分 []0None,但可以很好地处理 OCaml 内置类型。这样的函数可以在各种不同修改的库中找到,例如,Extlib and Batteries 库提供了一个在 dump 名称下的函数,这里是一个与它的顶层交互的例子:

# #use "topfind";;
# #require "extlib";;
# Std.dump;;
- : 'a -> string = <fun>
# Std.dump ["hello"; "world"];;
- : string = "[\"hello\"; \"world\"]"
# Std.dump [];;
- : string = "0"
# Std.dump None;;
- : string = "0"
# Std.dump [|"hello"|];;
- : string = "(\"hello\")"
# module Abstract : sig type t val x : t end = 
   struct type t = string list let x = ["hello, world"] end;;
module Abstract : sig type t val x : t end
# Std.dump Abstract.x;;
- : string = "[\"hello, world\"]"
# 

尽管您拥有如此强大的功能,我仍然建议您仅将其用于调试目的。

最后,如果您对顶级漂亮打印的工作原理感到好奇,这里就是答案。事实上,它依赖于顶层可用的打字环境,顶层部分是解释器,部分是编译器。这个漂亮的打印设备仍然相当脆弱。