如何将OCaml值打印在顶层之外?

时间:2011-08-31 17:55:27

标签: ocaml pretty-print

OCaml repl(“toplevel”)具有丰富的打印功能,适用于任何类型,用户定义或其他类型。是否可以在顶层之外访问此功能,而不必为自己的整个类型集编写一组完全自定义的值打印机?

3 个答案:

答案 0 :(得分:11)

漂亮的印刷设施是顶层图书馆的一部分。您可以在toplevel/genprintval.ml中找到来源。这是可以理解的,考虑到它需要类型信息:你不能只是抛出任何价值,漂亮的打印机的选择是基于类型。

如果要在程序中使用此代码,则需要链接到顶层库(toplevellib.cma)或在genprintval中编译(这意味着引入类型检查器的足够位)分析类型,它可以变得非常大。)

调试器(debugger/printval.mldebugger/loadprinter.ml)中有类似的工具(但我认为不共享代码)。

您可以直接链接第三方库,并提供漂亮的打印功能。 ExtlibStd.dump提供了非常粗糙的设施(不基于类型)。 Jeremy Yallop和Jake Donham的Deriving是另一种方法。 This Caml Weekly News item提供了更多建议。

答案 1 :(得分:10)

OCaml Batteries Included库包含BatPervasives模块中的dump功能。它将任何值转换为字符串并返回它。您可以看到其源代码here。输出与顶层不同,因为某些信息在运行时丢失,例如抽象数据类型构造函数将成为整数。

答案 2 :(得分:2)

没有。从OCaml 4.06开始,编译器不会在运行时提供类型信息。因此,不可能有独立的程序可以很好地打印任何OCaml数据,而不会有任何妥协。两个主要途径是:

  1. 某种形式的预处理,它从类型定义派生打印机。今天,最好的方法可能是show plugin of ppx-deriving。这需要注释每个类型定义。
  2. 仅依赖于值的运行时表示。这不需要程序员的努力,并且可以对外部库生成的数据进行开箱即用。但是,它不会显示记录字段名称或编译期间丢失的任何其他信息。下面详细介绍了这种方法的一个实例。
  3. 来自dum package的函数Dum.to_stdout将采用任何OCaml值,包括循环值,并在给定数据仅在运行时可用的情况下以人类可读的形式打印其物理表示。

    简单的事情会或多或少地提供人们的期望:

    # Dum.to_stdout ("Hello", 42, Some `Thing, [1;2;3]);;
    ("Hello" 42 (582416334) [ 1 2 3 ])
    

    循环 - 通常,使用标签和引用显示共享值。这是一份循环清单:

    # let rec cyc = 1 :: 2 :: cyc;;
    # Dum.to_stdout cyc;;
    #0: (1 (2 #0))
    

    我们还可以查看函数,模块和其他东西的运行时表示。例如,可以按如下方式检查Filename模块:

    # module type Filename = module type of Filename;;
    # Dum.to_stdout (module Filename : Filename);;
    (
      #0: "."
      ".."
      #1: "/"
      #2: closure (#1 #3: closure ())
      #4: closure ()
      closure (#4)
      closure ()
      closure ()
      closure (#5: closure (#3))
      closure (#5)
      closure (#5)
      closure (closure () #3 #0)
      closure (closure () #3 #0)
      closure (#6: closure (#2 <lazy>) #7: (#8))
      closure (#6 #7)
      closure (#7)
      closure (#7)
      #8: "/tmp"
      closure (closure () "'\\''")
    )