Ocaml的sprintf不能使用%a格式说明符

时间:2017-01-24 10:31:05

标签: ocaml format-specifiers

似乎sprintf在其格式说明符中不允许%a。这是正确的吗?如果是这样,为什么会这样,是否有解决方法?

示例。我有一个冗长而复杂的数据类型:

type t = Foo | Baz

我有一个这种类型的漂亮打印机,它将其值的字符串表示形式发送到任意out_channel

let pp_t oc = function
  | Foo -> fprintf oc "Foo"
  | Baz -> fprintf oc "Baz"

如果我再写

let _ = printf "%a=%d" pp_t Foo 2

let _ = eprintf "%a=%d" pp_t Foo 2

然后一切正常 - 消息" Foo = 2"按预期结束我的stdout或我的stderr。但如果我写

let s = sprintf "%a=%d" pp_t Foo 2

然后我收到编译错误,抱怨参数pp_t的类型为out_channel -> t -> unit,但表达式的类型为unit -> 'a -> string

是否根本无法在%a的格式说明符中使用sprintf

2 个答案:

答案 0 :(得分:3)

简短回答

使用Format模块进行漂亮的打印,使用Format.asprintf函数代替sprintf来构造字符串(我通常只在文件的开头做open Format

答案很长

可以将%a转化规范与sprintf一起使用。但是,所需函数的类型与Printf.fprintfPrintf.printf所需的类型不同。

所有漂亮的打印机(满足%a转换所需的值类型的函数)会对其类型中的输出类型进行编码。因此,对于printf函数的不同系列,您需要使用不同的漂亮打印功能。

对于Format模块漂亮打印机,您需要一个类型为formatter -> 'a -> unit的函数。这是顶级和调试器也需要的类型,它也是一种最常见的漂亮打印功能(像Core这样的库,以及许多其他库,提供满足的漂亮打印机)这个签名)。 Format模块还提供asprintf函数,与sprintf函数不同,它与%a转换效果很好(即它具有相同的formatter -> 'a -> unit类型)。

Printf.printf的情况下,漂亮打印机的类型应为out_channel -> 'a -> unit。这种类型的通用性要低得多,因此不如格式的那么流行。很少有图书馆提供一个。

最后,Printf.sprintf函数需要类型为unit -> 'a -> string的打印机。通常,获得这样漂亮的打印机的唯一方法是手动编写它(有时使用Printf.asprintf)。在你的情况下,它将是:

let pp_t () = function
  | Foo -> "Foo"
  | Baz -> "Baz"

答案 1 :(得分:2)

为了摆脱格式化功能中显示的特定数据类型,您应该始终使用Format模块并为具有签名val pp_t : Format.formatter -> t -> unit的类型设计漂亮的打印机;这也是toplevel要求为您的数据类型安装#install_printer的自定义打印机的签名。

配备此功能后,您只需将Format.asprintf"%a"一起使用。